Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
9
security/selinux/ss/Makefile
Normal file
9
security/selinux/ss/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for building the SELinux security server as part of the kernel tree.
|
||||
#
|
||||
|
||||
EXTRA_CFLAGS += -Isecurity/selinux/include
|
||||
obj-y := ss.o
|
||||
|
||||
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
|
||||
|
399
security/selinux/ss/avtab.c
Normal file
399
security/selinux/ss/avtab.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* Implementation of the access vector table type.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
|
||||
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
||||
*
|
||||
* Added conditional policy language extensions
|
||||
*
|
||||
* Copyright (C) 2003 Tresys Technology, LLC
|
||||
* 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
|
||||
* the Free Software Foundation, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "avtab.h"
|
||||
#include "policydb.h"
|
||||
|
||||
#define AVTAB_HASH(keyp) \
|
||||
((keyp->target_class + \
|
||||
(keyp->target_type << 2) + \
|
||||
(keyp->source_type << 9)) & \
|
||||
AVTAB_HASH_MASK)
|
||||
|
||||
static kmem_cache_t *avtab_node_cachep;
|
||||
|
||||
static struct avtab_node*
|
||||
avtab_insert_node(struct avtab *h, int hvalue,
|
||||
struct avtab_node * prev, struct avtab_node * cur,
|
||||
struct avtab_key *key, struct avtab_datum *datum)
|
||||
{
|
||||
struct avtab_node * newnode;
|
||||
newnode = kmem_cache_alloc(avtab_node_cachep, SLAB_KERNEL);
|
||||
if (newnode == NULL)
|
||||
return NULL;
|
||||
memset(newnode, 0, sizeof(struct avtab_node));
|
||||
newnode->key = *key;
|
||||
newnode->datum = *datum;
|
||||
if (prev) {
|
||||
newnode->next = prev->next;
|
||||
prev->next = newnode;
|
||||
} else {
|
||||
newnode->next = h->htable[hvalue];
|
||||
h->htable[hvalue] = newnode;
|
||||
}
|
||||
|
||||
h->nel++;
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
|
||||
{
|
||||
int hvalue;
|
||||
struct avtab_node *prev, *cur, *newnode;
|
||||
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
hvalue = AVTAB_HASH(key);
|
||||
for (prev = NULL, cur = h->htable[hvalue];
|
||||
cur;
|
||||
prev = cur, cur = cur->next) {
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class == cur->key.target_class &&
|
||||
(datum->specified & cur->datum.specified))
|
||||
return -EEXIST;
|
||||
if (key->source_type < cur->key.source_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type < cur->key.target_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
|
||||
newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
|
||||
if(!newnode)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlike avtab_insert(), this function allow multiple insertions of the same
|
||||
* key/specified mask into the table, as needed by the conditional avtab.
|
||||
* It also returns a pointer to the node inserted.
|
||||
*/
|
||||
struct avtab_node *
|
||||
avtab_insert_nonunique(struct avtab * h, struct avtab_key * key, struct avtab_datum * datum)
|
||||
{
|
||||
int hvalue;
|
||||
struct avtab_node *prev, *cur, *newnode;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
hvalue = AVTAB_HASH(key);
|
||||
for (prev = NULL, cur = h->htable[hvalue];
|
||||
cur;
|
||||
prev = cur, cur = cur->next) {
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class == cur->key.target_class &&
|
||||
(datum->specified & cur->datum.specified))
|
||||
break;
|
||||
if (key->source_type < cur->key.source_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type < cur->key.target_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key, int specified)
|
||||
{
|
||||
int hvalue;
|
||||
struct avtab_node *cur;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
hvalue = AVTAB_HASH(key);
|
||||
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class == cur->key.target_class &&
|
||||
(specified & cur->datum.specified))
|
||||
return &cur->datum;
|
||||
|
||||
if (key->source_type < cur->key.source_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type < cur->key.target_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This search function returns a node pointer, and can be used in
|
||||
* conjunction with avtab_search_next_node()
|
||||
*/
|
||||
struct avtab_node*
|
||||
avtab_search_node(struct avtab *h, struct avtab_key *key, int specified)
|
||||
{
|
||||
int hvalue;
|
||||
struct avtab_node *cur;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
hvalue = AVTAB_HASH(key);
|
||||
for (cur = h->htable[hvalue]; cur; cur = cur->next) {
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class == cur->key.target_class &&
|
||||
(specified & cur->datum.specified))
|
||||
return cur;
|
||||
|
||||
if (key->source_type < cur->key.source_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type < cur->key.target_type)
|
||||
break;
|
||||
if (key->source_type == cur->key.source_type &&
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct avtab_node*
|
||||
avtab_search_node_next(struct avtab_node *node, int specified)
|
||||
{
|
||||
struct avtab_node *cur;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
for (cur = node->next; cur; cur = cur->next) {
|
||||
if (node->key.source_type == cur->key.source_type &&
|
||||
node->key.target_type == cur->key.target_type &&
|
||||
node->key.target_class == cur->key.target_class &&
|
||||
(specified & cur->datum.specified))
|
||||
return cur;
|
||||
|
||||
if (node->key.source_type < cur->key.source_type)
|
||||
break;
|
||||
if (node->key.source_type == cur->key.source_type &&
|
||||
node->key.target_type < cur->key.target_type)
|
||||
break;
|
||||
if (node->key.source_type == cur->key.source_type &&
|
||||
node->key.target_type == cur->key.target_type &&
|
||||
node->key.target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void avtab_destroy(struct avtab *h)
|
||||
{
|
||||
int i;
|
||||
struct avtab_node *cur, *temp;
|
||||
|
||||
if (!h || !h->htable)
|
||||
return;
|
||||
|
||||
for (i = 0; i < AVTAB_SIZE; i++) {
|
||||
cur = h->htable[i];
|
||||
while (cur != NULL) {
|
||||
temp = cur;
|
||||
cur = cur->next;
|
||||
kmem_cache_free(avtab_node_cachep, temp);
|
||||
}
|
||||
h->htable[i] = NULL;
|
||||
}
|
||||
vfree(h->htable);
|
||||
h->htable = NULL;
|
||||
}
|
||||
|
||||
|
||||
int avtab_init(struct avtab *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
h->htable = vmalloc(sizeof(*(h->htable)) * AVTAB_SIZE);
|
||||
if (!h->htable)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < AVTAB_SIZE; i++)
|
||||
h->htable[i] = NULL;
|
||||
h->nel = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void avtab_hash_eval(struct avtab *h, char *tag)
|
||||
{
|
||||
int i, chain_len, slots_used, max_chain_len;
|
||||
struct avtab_node *cur;
|
||||
|
||||
slots_used = 0;
|
||||
max_chain_len = 0;
|
||||
for (i = 0; i < AVTAB_SIZE; i++) {
|
||||
cur = h->htable[i];
|
||||
if (cur) {
|
||||
slots_used++;
|
||||
chain_len = 0;
|
||||
while (cur) {
|
||||
chain_len++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (chain_len > max_chain_len)
|
||||
max_chain_len = chain_len;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
|
||||
"chain length %d\n", tag, h->nel, slots_used, AVTAB_SIZE,
|
||||
max_chain_len);
|
||||
}
|
||||
|
||||
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey)
|
||||
{
|
||||
u32 buf[7];
|
||||
u32 items, items2;
|
||||
int rc;
|
||||
|
||||
memset(avkey, 0, sizeof(struct avtab_key));
|
||||
memset(avdatum, 0, sizeof(struct avtab_datum));
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "security: avtab: truncated entry\n");
|
||||
goto bad;
|
||||
}
|
||||
items2 = le32_to_cpu(buf[0]);
|
||||
if (items2 > ARRAY_SIZE(buf)) {
|
||||
printk(KERN_ERR "security: avtab: entry overflow\n");
|
||||
goto bad;
|
||||
}
|
||||
rc = next_entry(buf, fp, sizeof(u32)*items2);
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "security: avtab: truncated entry\n");
|
||||
goto bad;
|
||||
}
|
||||
items = 0;
|
||||
avkey->source_type = le32_to_cpu(buf[items++]);
|
||||
avkey->target_type = le32_to_cpu(buf[items++]);
|
||||
avkey->target_class = le32_to_cpu(buf[items++]);
|
||||
avdatum->specified = le32_to_cpu(buf[items++]);
|
||||
if (!(avdatum->specified & (AVTAB_AV | AVTAB_TYPE))) {
|
||||
printk(KERN_ERR "security: avtab: null entry\n");
|
||||
goto bad;
|
||||
}
|
||||
if ((avdatum->specified & AVTAB_AV) &&
|
||||
(avdatum->specified & AVTAB_TYPE)) {
|
||||
printk(KERN_ERR "security: avtab: entry has both access vectors and types\n");
|
||||
goto bad;
|
||||
}
|
||||
if (avdatum->specified & AVTAB_AV) {
|
||||
if (avdatum->specified & AVTAB_ALLOWED)
|
||||
avtab_allowed(avdatum) = le32_to_cpu(buf[items++]);
|
||||
if (avdatum->specified & AVTAB_AUDITDENY)
|
||||
avtab_auditdeny(avdatum) = le32_to_cpu(buf[items++]);
|
||||
if (avdatum->specified & AVTAB_AUDITALLOW)
|
||||
avtab_auditallow(avdatum) = le32_to_cpu(buf[items++]);
|
||||
} else {
|
||||
if (avdatum->specified & AVTAB_TRANSITION)
|
||||
avtab_transition(avdatum) = le32_to_cpu(buf[items++]);
|
||||
if (avdatum->specified & AVTAB_CHANGE)
|
||||
avtab_change(avdatum) = le32_to_cpu(buf[items++]);
|
||||
if (avdatum->specified & AVTAB_MEMBER)
|
||||
avtab_member(avdatum) = le32_to_cpu(buf[items++]);
|
||||
}
|
||||
if (items != items2) {
|
||||
printk(KERN_ERR "security: avtab: entry only had %d items, expected %d\n",
|
||||
items2, items);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int avtab_read(struct avtab *a, void *fp, u32 config)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_key avkey;
|
||||
struct avtab_datum avdatum;
|
||||
u32 buf[1];
|
||||
u32 nel, i;
|
||||
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "security: avtab: truncated table\n");
|
||||
goto bad;
|
||||
}
|
||||
nel = le32_to_cpu(buf[0]);
|
||||
if (!nel) {
|
||||
printk(KERN_ERR "security: avtab: table is empty\n");
|
||||
rc = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
for (i = 0; i < nel; i++) {
|
||||
if (avtab_read_item(fp, &avdatum, &avkey)) {
|
||||
rc = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
rc = avtab_insert(a, &avkey, &avdatum);
|
||||
if (rc) {
|
||||
if (rc == -ENOMEM)
|
||||
printk(KERN_ERR "security: avtab: out of memory\n");
|
||||
if (rc == -EEXIST)
|
||||
printk(KERN_ERR "security: avtab: duplicate entry\n");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
return rc;
|
||||
|
||||
bad:
|
||||
avtab_destroy(a);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void avtab_cache_init(void)
|
||||
{
|
||||
avtab_node_cachep = kmem_cache_create("avtab_node",
|
||||
sizeof(struct avtab_node),
|
||||
0, SLAB_PANIC, NULL, NULL);
|
||||
}
|
||||
|
||||
void avtab_cache_destroy(void)
|
||||
{
|
||||
kmem_cache_destroy (avtab_node_cachep);
|
||||
}
|
85
security/selinux/ss/avtab.h
Normal file
85
security/selinux/ss/avtab.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* An access vector table (avtab) is a hash table
|
||||
* of access vectors and transition types indexed
|
||||
* by a type pair and a class. An access vector
|
||||
* table is used to represent the type enforcement
|
||||
* tables.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
|
||||
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
||||
*
|
||||
* Added conditional policy language extensions
|
||||
*
|
||||
* Copyright (C) 2003 Tresys Technology, LLC
|
||||
* 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
|
||||
* the Free Software Foundation, version 2.
|
||||
*/
|
||||
#ifndef _SS_AVTAB_H_
|
||||
#define _SS_AVTAB_H_
|
||||
|
||||
struct avtab_key {
|
||||
u32 source_type; /* source type */
|
||||
u32 target_type; /* target type */
|
||||
u32 target_class; /* target object class */
|
||||
};
|
||||
|
||||
struct avtab_datum {
|
||||
#define AVTAB_ALLOWED 1
|
||||
#define AVTAB_AUDITALLOW 2
|
||||
#define AVTAB_AUDITDENY 4
|
||||
#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
|
||||
#define AVTAB_TRANSITION 16
|
||||
#define AVTAB_MEMBER 32
|
||||
#define AVTAB_CHANGE 64
|
||||
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
|
||||
#define AVTAB_ENABLED 0x80000000 /* reserved for used in cond_avtab */
|
||||
u32 specified; /* what fields are specified */
|
||||
u32 data[3]; /* access vectors or types */
|
||||
#define avtab_allowed(x) (x)->data[0]
|
||||
#define avtab_auditdeny(x) (x)->data[1]
|
||||
#define avtab_auditallow(x) (x)->data[2]
|
||||
#define avtab_transition(x) (x)->data[0]
|
||||
#define avtab_change(x) (x)->data[1]
|
||||
#define avtab_member(x) (x)->data[2]
|
||||
};
|
||||
|
||||
struct avtab_node {
|
||||
struct avtab_key key;
|
||||
struct avtab_datum datum;
|
||||
struct avtab_node *next;
|
||||
};
|
||||
|
||||
struct avtab {
|
||||
struct avtab_node **htable;
|
||||
u32 nel; /* number of elements */
|
||||
};
|
||||
|
||||
int avtab_init(struct avtab *);
|
||||
struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k, int specified);
|
||||
void avtab_destroy(struct avtab *h);
|
||||
void avtab_hash_eval(struct avtab *h, char *tag);
|
||||
|
||||
int avtab_read_item(void *fp, struct avtab_datum *avdatum, struct avtab_key *avkey);
|
||||
int avtab_read(struct avtab *a, void *fp, u32 config);
|
||||
|
||||
struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
|
||||
struct avtab_datum *datum);
|
||||
|
||||
struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key, int specified);
|
||||
|
||||
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
|
||||
|
||||
void avtab_cache_init(void);
|
||||
void avtab_cache_destroy(void);
|
||||
|
||||
#define AVTAB_HASH_BITS 15
|
||||
#define AVTAB_HASH_BUCKETS (1 << AVTAB_HASH_BITS)
|
||||
#define AVTAB_HASH_MASK (AVTAB_HASH_BUCKETS-1)
|
||||
|
||||
#define AVTAB_SIZE AVTAB_HASH_BUCKETS
|
||||
|
||||
#endif /* _SS_AVTAB_H_ */
|
||||
|
489
security/selinux/ss/conditional.c
Normal file
489
security/selinux/ss/conditional.c
Normal file
@@ -0,0 +1,489 @@
|
||||
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
|
||||
* Frank Mayer <mayerf@tresys.com>
|
||||
*
|
||||
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
||||
* 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
|
||||
* the Free Software Foundation, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "security.h"
|
||||
#include "conditional.h"
|
||||
|
||||
/*
|
||||
* cond_evaluate_expr evaluates a conditional expr
|
||||
* in reverse polish notation. It returns true (1), false (0),
|
||||
* or undefined (-1). Undefined occurs when the expression
|
||||
* exceeds the stack depth of COND_EXPR_MAXDEPTH.
|
||||
*/
|
||||
static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
|
||||
{
|
||||
|
||||
struct cond_expr *cur;
|
||||
int s[COND_EXPR_MAXDEPTH];
|
||||
int sp = -1;
|
||||
|
||||
for (cur = expr; cur != NULL; cur = cur->next) {
|
||||
switch (cur->expr_type) {
|
||||
case COND_BOOL:
|
||||
if (sp == (COND_EXPR_MAXDEPTH - 1))
|
||||
return -1;
|
||||
sp++;
|
||||
s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
|
||||
break;
|
||||
case COND_NOT:
|
||||
if (sp < 0)
|
||||
return -1;
|
||||
s[sp] = !s[sp];
|
||||
break;
|
||||
case COND_OR:
|
||||
if (sp < 1)
|
||||
return -1;
|
||||
sp--;
|
||||
s[sp] |= s[sp + 1];
|
||||
break;
|
||||
case COND_AND:
|
||||
if (sp < 1)
|
||||
return -1;
|
||||
sp--;
|
||||
s[sp] &= s[sp + 1];
|
||||
break;
|
||||
case COND_XOR:
|
||||
if (sp < 1)
|
||||
return -1;
|
||||
sp--;
|
||||
s[sp] ^= s[sp + 1];
|
||||
break;
|
||||
case COND_EQ:
|
||||
if (sp < 1)
|
||||
return -1;
|
||||
sp--;
|
||||
s[sp] = (s[sp] == s[sp + 1]);
|
||||
break;
|
||||
case COND_NEQ:
|
||||
if (sp < 1)
|
||||
return -1;
|
||||
sp--;
|
||||
s[sp] = (s[sp] != s[sp + 1]);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return s[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* evaluate_cond_node evaluates the conditional stored in
|
||||
* a struct cond_node and if the result is different than the
|
||||
* current state of the node it sets the rules in the true/false
|
||||
* list appropriately. If the result of the expression is undefined
|
||||
* all of the rules are disabled for safety.
|
||||
*/
|
||||
int evaluate_cond_node(struct policydb *p, struct cond_node *node)
|
||||
{
|
||||
int new_state;
|
||||
struct cond_av_list* cur;
|
||||
|
||||
new_state = cond_evaluate_expr(p, node->expr);
|
||||
if (new_state != node->cur_state) {
|
||||
node->cur_state = new_state;
|
||||
if (new_state == -1)
|
||||
printk(KERN_ERR "security: expression result was undefined - disabling all rules.\n");
|
||||
/* turn the rules on or off */
|
||||
for (cur = node->true_list; cur != NULL; cur = cur->next) {
|
||||
if (new_state <= 0) {
|
||||
cur->node->datum.specified &= ~AVTAB_ENABLED;
|
||||
} else {
|
||||
cur->node->datum.specified |= AVTAB_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
for (cur = node->false_list; cur != NULL; cur = cur->next) {
|
||||
/* -1 or 1 */
|
||||
if (new_state) {
|
||||
cur->node->datum.specified &= ~AVTAB_ENABLED;
|
||||
} else {
|
||||
cur->node->datum.specified |= AVTAB_ENABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cond_policydb_init(struct policydb *p)
|
||||
{
|
||||
p->bool_val_to_struct = NULL;
|
||||
p->cond_list = NULL;
|
||||
if (avtab_init(&p->te_cond_avtab))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cond_av_list_destroy(struct cond_av_list *list)
|
||||
{
|
||||
struct cond_av_list *cur, *next;
|
||||
for (cur = list; cur != NULL; cur = next) {
|
||||
next = cur->next;
|
||||
/* the avtab_ptr_t node is destroy by the avtab */
|
||||
kfree(cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void cond_node_destroy(struct cond_node *node)
|
||||
{
|
||||
struct cond_expr *cur_expr, *next_expr;
|
||||
|
||||
for (cur_expr = node->expr; cur_expr != NULL; cur_expr = next_expr) {
|
||||
next_expr = cur_expr->next;
|
||||
kfree(cur_expr);
|
||||
}
|
||||
cond_av_list_destroy(node->true_list);
|
||||
cond_av_list_destroy(node->false_list);
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
static void cond_list_destroy(struct cond_node *list)
|
||||
{
|
||||
struct cond_node *next, *cur;
|
||||
|
||||
if (list == NULL)
|
||||
return;
|
||||
|
||||
for (cur = list; cur != NULL; cur = next) {
|
||||
next = cur->next;
|
||||
cond_node_destroy(cur);
|
||||
}
|
||||
}
|
||||
|
||||
void cond_policydb_destroy(struct policydb *p)
|
||||
{
|
||||
if (p->bool_val_to_struct != NULL)
|
||||
kfree(p->bool_val_to_struct);
|
||||
avtab_destroy(&p->te_cond_avtab);
|
||||
cond_list_destroy(p->cond_list);
|
||||
}
|
||||
|
||||
int cond_init_bool_indexes(struct policydb *p)
|
||||
{
|
||||
if (p->bool_val_to_struct)
|
||||
kfree(p->bool_val_to_struct);
|
||||
p->bool_val_to_struct = (struct cond_bool_datum**)
|
||||
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
|
||||
if (!p->bool_val_to_struct)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cond_destroy_bool(void *key, void *datum, void *p)
|
||||
{
|
||||
if (key)
|
||||
kfree(key);
|
||||
kfree(datum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cond_index_bool(void *key, void *datum, void *datap)
|
||||
{
|
||||
struct policydb *p;
|
||||
struct cond_bool_datum *booldatum;
|
||||
|
||||
booldatum = datum;
|
||||
p = datap;
|
||||
|
||||
if (!booldatum->value || booldatum->value > p->p_bools.nprim)
|
||||
return -EINVAL;
|
||||
|
||||
p->p_bool_val_to_name[booldatum->value - 1] = key;
|
||||
p->bool_val_to_struct[booldatum->value -1] = booldatum;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bool_isvalid(struct cond_bool_datum *b)
|
||||
{
|
||||
if (!(b->state == 0 || b->state == 1))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
|
||||
{
|
||||
char *key = NULL;
|
||||
struct cond_bool_datum *booldatum;
|
||||
u32 buf[3], len;
|
||||
int rc;
|
||||
|
||||
booldatum = kmalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
|
||||
if (!booldatum)
|
||||
return -1;
|
||||
memset(booldatum, 0, sizeof(struct cond_bool_datum));
|
||||
|
||||
rc = next_entry(buf, fp, sizeof buf);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
booldatum->value = le32_to_cpu(buf[0]);
|
||||
booldatum->state = le32_to_cpu(buf[1]);
|
||||
|
||||
if (!bool_isvalid(booldatum))
|
||||
goto err;
|
||||
|
||||
len = le32_to_cpu(buf[2]);
|
||||
|
||||
key = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (!key)
|
||||
goto err;
|
||||
rc = next_entry(key, fp, len);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
key[len] = 0;
|
||||
if (hashtab_insert(h, key, booldatum))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
cond_destroy_bool(key, booldatum, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list,
|
||||
struct cond_av_list *other)
|
||||
{
|
||||
struct cond_av_list *list, *last = NULL, *cur;
|
||||
struct avtab_key key;
|
||||
struct avtab_datum datum;
|
||||
struct avtab_node *node_ptr;
|
||||
int rc;
|
||||
u32 buf[1], i, len;
|
||||
u8 found;
|
||||
|
||||
*ret_list = NULL;
|
||||
|
||||
len = 0;
|
||||
rc = next_entry(buf, fp, sizeof buf);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
len = le32_to_cpu(buf[0]);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (avtab_read_item(fp, &datum, &key))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* For type rules we have to make certain there aren't any
|
||||
* conflicting rules by searching the te_avtab and the
|
||||
* cond_te_avtab.
|
||||
*/
|
||||
if (datum.specified & AVTAB_TYPE) {
|
||||
if (avtab_search(&p->te_avtab, &key, AVTAB_TYPE)) {
|
||||
printk("security: type rule already exists outside of a conditional.");
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* If we are reading the false list other will be a pointer to
|
||||
* the true list. We can have duplicate entries if there is only
|
||||
* 1 other entry and it is in our true list.
|
||||
*
|
||||
* If we are reading the true list (other == NULL) there shouldn't
|
||||
* be any other entries.
|
||||
*/
|
||||
if (other) {
|
||||
node_ptr = avtab_search_node(&p->te_cond_avtab, &key, AVTAB_TYPE);
|
||||
if (node_ptr) {
|
||||
if (avtab_search_node_next(node_ptr, AVTAB_TYPE)) {
|
||||
printk("security: too many conflicting type rules.");
|
||||
goto err;
|
||||
}
|
||||
found = 0;
|
||||
for (cur = other; cur != NULL; cur = cur->next) {
|
||||
if (cur->node == node_ptr) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
printk("security: conflicting type rules.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (avtab_search(&p->te_cond_avtab, &key, AVTAB_TYPE)) {
|
||||
printk("security: conflicting type rules when adding type rule for true.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, &key, &datum);
|
||||
if (!node_ptr) {
|
||||
printk("security: could not insert rule.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
list = kmalloc(sizeof(struct cond_av_list), GFP_KERNEL);
|
||||
if (!list)
|
||||
goto err;
|
||||
memset(list, 0, sizeof(struct cond_av_list));
|
||||
|
||||
list->node = node_ptr;
|
||||
if (i == 0)
|
||||
*ret_list = list;
|
||||
else
|
||||
last->next = list;
|
||||
last = list;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
cond_av_list_destroy(*ret_list);
|
||||
*ret_list = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
|
||||
{
|
||||
if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
|
||||
printk("security: conditional expressions uses unknown operator.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (expr->bool > p->p_bools.nprim) {
|
||||
printk("security: conditional expressions uses unknown bool.\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
|
||||
{
|
||||
u32 buf[2], len, i;
|
||||
int rc;
|
||||
struct cond_expr *expr = NULL, *last = NULL;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
node->cur_state = le32_to_cpu(buf[0]);
|
||||
|
||||
len = 0;
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
/* expr */
|
||||
len = le32_to_cpu(buf[0]);
|
||||
|
||||
for (i = 0; i < len; i++ ) {
|
||||
rc = next_entry(buf, fp, sizeof(u32) * 2);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
expr = kmalloc(sizeof(struct cond_expr), GFP_KERNEL);
|
||||
if (!expr) {
|
||||
goto err;
|
||||
}
|
||||
memset(expr, 0, sizeof(struct cond_expr));
|
||||
|
||||
expr->expr_type = le32_to_cpu(buf[0]);
|
||||
expr->bool = le32_to_cpu(buf[1]);
|
||||
|
||||
if (!expr_isvalid(p, expr)) {
|
||||
kfree(expr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
node->expr = expr;
|
||||
} else {
|
||||
last->next = expr;
|
||||
}
|
||||
last = expr;
|
||||
}
|
||||
|
||||
if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
|
||||
goto err;
|
||||
if (cond_read_av_list(p, fp, &node->false_list, node->true_list) != 0)
|
||||
goto err;
|
||||
return 0;
|
||||
err:
|
||||
cond_node_destroy(node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cond_read_list(struct policydb *p, void *fp)
|
||||
{
|
||||
struct cond_node *node, *last = NULL;
|
||||
u32 buf[1], i, len;
|
||||
int rc;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof buf);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
len = le32_to_cpu(buf[0]);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
node = kmalloc(sizeof(struct cond_node), GFP_KERNEL);
|
||||
if (!node)
|
||||
goto err;
|
||||
memset(node, 0, sizeof(struct cond_node));
|
||||
|
||||
if (cond_read_node(p, node, fp) != 0)
|
||||
goto err;
|
||||
|
||||
if (i == 0) {
|
||||
p->cond_list = node;
|
||||
} else {
|
||||
last->next = node;
|
||||
}
|
||||
last = node;
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
cond_list_destroy(p->cond_list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Determine whether additional permissions are granted by the conditional
|
||||
* av table, and if so, add them to the result
|
||||
*/
|
||||
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
|
||||
{
|
||||
struct avtab_node *node;
|
||||
|
||||
if(!ctab || !key || !avd)
|
||||
return;
|
||||
|
||||
for(node = avtab_search_node(ctab, key, AVTAB_AV); node != NULL;
|
||||
node = avtab_search_node_next(node, AVTAB_AV)) {
|
||||
if ( (__u32) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
|
||||
(node->datum.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
|
||||
avd->allowed |= avtab_allowed(&node->datum);
|
||||
if ( (__u32) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
|
||||
(node->datum.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
|
||||
/* Since a '0' in an auditdeny mask represents a
|
||||
* permission we do NOT want to audit (dontaudit), we use
|
||||
* the '&' operand to ensure that all '0's in the mask
|
||||
* are retained (much unlike the allow and auditallow cases).
|
||||
*/
|
||||
avd->auditdeny &= avtab_auditdeny(&node->datum);
|
||||
if ( (__u32) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
|
||||
(node->datum.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
|
||||
avd->auditallow |= avtab_auditallow(&node->datum);
|
||||
}
|
||||
return;
|
||||
}
|
77
security/selinux/ss/conditional.h
Normal file
77
security/selinux/ss/conditional.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
|
||||
* Frank Mayer <mayerf@tresys.com>
|
||||
*
|
||||
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
||||
* 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
|
||||
* the Free Software Foundation, version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CONDITIONAL_H_
|
||||
#define _CONDITIONAL_H_
|
||||
|
||||
#include "avtab.h"
|
||||
#include "symtab.h"
|
||||
#include "policydb.h"
|
||||
|
||||
#define COND_EXPR_MAXDEPTH 10
|
||||
|
||||
/*
|
||||
* A conditional expression is a list of operators and operands
|
||||
* in reverse polish notation.
|
||||
*/
|
||||
struct cond_expr {
|
||||
#define COND_BOOL 1 /* plain bool */
|
||||
#define COND_NOT 2 /* !bool */
|
||||
#define COND_OR 3 /* bool || bool */
|
||||
#define COND_AND 4 /* bool && bool */
|
||||
#define COND_XOR 5 /* bool ^ bool */
|
||||
#define COND_EQ 6 /* bool == bool */
|
||||
#define COND_NEQ 7 /* bool != bool */
|
||||
#define COND_LAST 8
|
||||
__u32 expr_type;
|
||||
__u32 bool;
|
||||
struct cond_expr *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Each cond_node contains a list of rules to be enabled/disabled
|
||||
* depending on the current value of the conditional expression. This
|
||||
* struct is for that list.
|
||||
*/
|
||||
struct cond_av_list {
|
||||
struct avtab_node *node;
|
||||
struct cond_av_list *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* A cond node represents a conditional block in a policy. It
|
||||
* contains a conditional expression, the current state of the expression,
|
||||
* two lists of rules to enable/disable depending on the value of the
|
||||
* expression (the true list corresponds to if and the false list corresponds
|
||||
* to else)..
|
||||
*/
|
||||
struct cond_node {
|
||||
int cur_state;
|
||||
struct cond_expr *expr;
|
||||
struct cond_av_list *true_list;
|
||||
struct cond_av_list *false_list;
|
||||
struct cond_node *next;
|
||||
};
|
||||
|
||||
int cond_policydb_init(struct policydb* p);
|
||||
void cond_policydb_destroy(struct policydb* p);
|
||||
|
||||
int cond_init_bool_indexes(struct policydb* p);
|
||||
int cond_destroy_bool(void *key, void *datum, void *p);
|
||||
|
||||
int cond_index_bool(void *key, void *datum, void *datap);
|
||||
|
||||
int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
|
||||
int cond_read_list(struct policydb *p, void *fp);
|
||||
|
||||
void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
|
||||
|
||||
int evaluate_cond_node(struct policydb *p, struct cond_node *node);
|
||||
|
||||
#endif /* _CONDITIONAL_H_ */
|
61
security/selinux/ss/constraint.h
Normal file
61
security/selinux/ss/constraint.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* A constraint is a condition that must be satisfied in
|
||||
* order for one or more permissions to be granted.
|
||||
* Constraints are used to impose additional restrictions
|
||||
* beyond the type-based rules in `te' or the role-based
|
||||
* transition rules in `rbac'. Constraints are typically
|
||||
* used to prevent a process from transitioning to a new user
|
||||
* identity or role unless it is in a privileged type.
|
||||
* Constraints are likewise typically used to prevent a
|
||||
* process from labeling an object with a different user
|
||||
* identity.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_CONSTRAINT_H_
|
||||
#define _SS_CONSTRAINT_H_
|
||||
|
||||
#include "ebitmap.h"
|
||||
|
||||
#define CEXPR_MAXDEPTH 5
|
||||
|
||||
struct constraint_expr {
|
||||
#define CEXPR_NOT 1 /* not expr */
|
||||
#define CEXPR_AND 2 /* expr and expr */
|
||||
#define CEXPR_OR 3 /* expr or expr */
|
||||
#define CEXPR_ATTR 4 /* attr op attr */
|
||||
#define CEXPR_NAMES 5 /* attr op names */
|
||||
u32 expr_type; /* expression type */
|
||||
|
||||
#define CEXPR_USER 1 /* user */
|
||||
#define CEXPR_ROLE 2 /* role */
|
||||
#define CEXPR_TYPE 4 /* type */
|
||||
#define CEXPR_TARGET 8 /* target if set, source otherwise */
|
||||
#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
|
||||
#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
|
||||
#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
|
||||
#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
|
||||
#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
|
||||
#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
|
||||
#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
|
||||
u32 attr; /* attribute */
|
||||
|
||||
#define CEXPR_EQ 1 /* == or eq */
|
||||
#define CEXPR_NEQ 2 /* != */
|
||||
#define CEXPR_DOM 3 /* dom */
|
||||
#define CEXPR_DOMBY 4 /* domby */
|
||||
#define CEXPR_INCOMP 5 /* incomp */
|
||||
u32 op; /* operator */
|
||||
|
||||
struct ebitmap names; /* names */
|
||||
|
||||
struct constraint_expr *next; /* next expression */
|
||||
};
|
||||
|
||||
struct constraint_node {
|
||||
u32 permissions; /* constrained permissions */
|
||||
struct constraint_expr *expr; /* constraint on permissions */
|
||||
struct constraint_node *next; /* next constraint */
|
||||
};
|
||||
|
||||
#endif /* _SS_CONSTRAINT_H_ */
|
107
security/selinux/ss/context.h
Normal file
107
security/selinux/ss/context.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* A security context is a set of security attributes
|
||||
* associated with each subject and object controlled
|
||||
* by the security policy. Security contexts are
|
||||
* externally represented as variable-length strings
|
||||
* that can be interpreted by a user or application
|
||||
* with an understanding of the security policy.
|
||||
* Internally, the security server uses a simple
|
||||
* structure. This structure is private to the
|
||||
* security server and can be changed without affecting
|
||||
* clients of the security server.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_CONTEXT_H_
|
||||
#define _SS_CONTEXT_H_
|
||||
|
||||
#include "ebitmap.h"
|
||||
#include "mls_types.h"
|
||||
#include "security.h"
|
||||
|
||||
/*
|
||||
* A security context consists of an authenticated user
|
||||
* identity, a role, a type and a MLS range.
|
||||
*/
|
||||
struct context {
|
||||
u32 user;
|
||||
u32 role;
|
||||
u32 type;
|
||||
struct mls_range range;
|
||||
};
|
||||
|
||||
static inline void mls_context_init(struct context *c)
|
||||
{
|
||||
memset(&c->range, 0, sizeof(c->range));
|
||||
}
|
||||
|
||||
static inline int mls_context_cpy(struct context *dst, struct context *src)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
dst->range.level[0].sens = src->range.level[0].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
dst->range.level[1].sens = src->range.level[1].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat);
|
||||
if (rc)
|
||||
ebitmap_destroy(&dst->range.level[0].cat);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int mls_context_cmp(struct context *c1, struct context *c2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
|
||||
ebitmap_cmp(&c1->range.level[0].cat,&c2->range.level[0].cat) &&
|
||||
(c1->range.level[1].sens == c2->range.level[1].sens) &&
|
||||
ebitmap_cmp(&c1->range.level[1].cat,&c2->range.level[1].cat));
|
||||
}
|
||||
|
||||
static inline void mls_context_destroy(struct context *c)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return;
|
||||
|
||||
ebitmap_destroy(&c->range.level[0].cat);
|
||||
ebitmap_destroy(&c->range.level[1].cat);
|
||||
mls_context_init(c);
|
||||
}
|
||||
|
||||
static inline void context_init(struct context *c)
|
||||
{
|
||||
memset(c, 0, sizeof(*c));
|
||||
}
|
||||
|
||||
static inline int context_cpy(struct context *dst, struct context *src)
|
||||
{
|
||||
dst->user = src->user;
|
||||
dst->role = src->role;
|
||||
dst->type = src->type;
|
||||
return mls_context_cpy(dst, src);
|
||||
}
|
||||
|
||||
static inline void context_destroy(struct context *c)
|
||||
{
|
||||
c->user = c->role = c->type = 0;
|
||||
mls_context_destroy(c);
|
||||
}
|
||||
|
||||
static inline int context_cmp(struct context *c1, struct context *c2)
|
||||
{
|
||||
return ((c1->user == c2->user) &&
|
||||
(c1->role == c2->role) &&
|
||||
(c1->type == c2->type) &&
|
||||
mls_context_cmp(c1, c2));
|
||||
}
|
||||
|
||||
#endif /* _SS_CONTEXT_H_ */
|
||||
|
293
security/selinux/ss/ebitmap.c
Normal file
293
security/selinux/ss/ebitmap.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Implementation of the extensible bitmap type.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include "ebitmap.h"
|
||||
#include "policydb.h"
|
||||
|
||||
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
|
||||
{
|
||||
struct ebitmap_node *n1, *n2;
|
||||
|
||||
if (e1->highbit != e2->highbit)
|
||||
return 0;
|
||||
|
||||
n1 = e1->node;
|
||||
n2 = e2->node;
|
||||
while (n1 && n2 &&
|
||||
(n1->startbit == n2->startbit) &&
|
||||
(n1->map == n2->map)) {
|
||||
n1 = n1->next;
|
||||
n2 = n2->next;
|
||||
}
|
||||
|
||||
if (n1 || n2)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
|
||||
{
|
||||
struct ebitmap_node *n, *new, *prev;
|
||||
|
||||
ebitmap_init(dst);
|
||||
n = src->node;
|
||||
prev = NULL;
|
||||
while (n) {
|
||||
new = kmalloc(sizeof(*new), GFP_ATOMIC);
|
||||
if (!new) {
|
||||
ebitmap_destroy(dst);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(new, 0, sizeof(*new));
|
||||
new->startbit = n->startbit;
|
||||
new->map = n->map;
|
||||
new->next = NULL;
|
||||
if (prev)
|
||||
prev->next = new;
|
||||
else
|
||||
dst->node = new;
|
||||
prev = new;
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
dst->highbit = src->highbit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
|
||||
{
|
||||
struct ebitmap_node *n1, *n2;
|
||||
|
||||
if (e1->highbit < e2->highbit)
|
||||
return 0;
|
||||
|
||||
n1 = e1->node;
|
||||
n2 = e2->node;
|
||||
while (n1 && n2 && (n1->startbit <= n2->startbit)) {
|
||||
if (n1->startbit < n2->startbit) {
|
||||
n1 = n1->next;
|
||||
continue;
|
||||
}
|
||||
if ((n1->map & n2->map) != n2->map)
|
||||
return 0;
|
||||
|
||||
n1 = n1->next;
|
||||
n2 = n2->next;
|
||||
}
|
||||
|
||||
if (n2)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
|
||||
{
|
||||
struct ebitmap_node *n;
|
||||
|
||||
if (e->highbit < bit)
|
||||
return 0;
|
||||
|
||||
n = e->node;
|
||||
while (n && (n->startbit <= bit)) {
|
||||
if ((n->startbit + MAPSIZE) > bit) {
|
||||
if (n->map & (MAPBIT << (bit - n->startbit)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
|
||||
{
|
||||
struct ebitmap_node *n, *prev, *new;
|
||||
|
||||
prev = NULL;
|
||||
n = e->node;
|
||||
while (n && n->startbit <= bit) {
|
||||
if ((n->startbit + MAPSIZE) > bit) {
|
||||
if (value) {
|
||||
n->map |= (MAPBIT << (bit - n->startbit));
|
||||
} else {
|
||||
n->map &= ~(MAPBIT << (bit - n->startbit));
|
||||
if (!n->map) {
|
||||
/* drop this node from the bitmap */
|
||||
|
||||
if (!n->next) {
|
||||
/*
|
||||
* this was the highest map
|
||||
* within the bitmap
|
||||
*/
|
||||
if (prev)
|
||||
e->highbit = prev->startbit + MAPSIZE;
|
||||
else
|
||||
e->highbit = 0;
|
||||
}
|
||||
if (prev)
|
||||
prev->next = n->next;
|
||||
else
|
||||
e->node = n->next;
|
||||
|
||||
kfree(n);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
prev = n;
|
||||
n = n->next;
|
||||
}
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
new = kmalloc(sizeof(*new), GFP_ATOMIC);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
memset(new, 0, sizeof(*new));
|
||||
|
||||
new->startbit = bit & ~(MAPSIZE - 1);
|
||||
new->map = (MAPBIT << (bit - new->startbit));
|
||||
|
||||
if (!n)
|
||||
/* this node will be the highest map within the bitmap */
|
||||
e->highbit = new->startbit + MAPSIZE;
|
||||
|
||||
if (prev) {
|
||||
new->next = prev->next;
|
||||
prev->next = new;
|
||||
} else {
|
||||
new->next = e->node;
|
||||
e->node = new;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ebitmap_destroy(struct ebitmap *e)
|
||||
{
|
||||
struct ebitmap_node *n, *temp;
|
||||
|
||||
if (!e)
|
||||
return;
|
||||
|
||||
n = e->node;
|
||||
while (n) {
|
||||
temp = n;
|
||||
n = n->next;
|
||||
kfree(temp);
|
||||
}
|
||||
|
||||
e->highbit = 0;
|
||||
e->node = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
int ebitmap_read(struct ebitmap *e, void *fp)
|
||||
{
|
||||
int rc;
|
||||
struct ebitmap_node *n, *l;
|
||||
u32 buf[3], mapsize, count, i;
|
||||
u64 map;
|
||||
|
||||
ebitmap_init(e);
|
||||
|
||||
rc = next_entry(buf, fp, sizeof buf);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
mapsize = le32_to_cpu(buf[0]);
|
||||
e->highbit = le32_to_cpu(buf[1]);
|
||||
count = le32_to_cpu(buf[2]);
|
||||
|
||||
if (mapsize != MAPSIZE) {
|
||||
printk(KERN_ERR "security: ebitmap: map size %u does not "
|
||||
"match my size %Zd (high bit was %d)\n", mapsize,
|
||||
MAPSIZE, e->highbit);
|
||||
goto bad;
|
||||
}
|
||||
if (!e->highbit) {
|
||||
e->node = NULL;
|
||||
goto ok;
|
||||
}
|
||||
if (e->highbit & (MAPSIZE - 1)) {
|
||||
printk(KERN_ERR "security: ebitmap: high bit (%d) is not a "
|
||||
"multiple of the map size (%Zd)\n", e->highbit, MAPSIZE);
|
||||
goto bad;
|
||||
}
|
||||
l = NULL;
|
||||
for (i = 0; i < count; i++) {
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "security: ebitmap: truncated map\n");
|
||||
goto bad;
|
||||
}
|
||||
n = kmalloc(sizeof(*n), GFP_KERNEL);
|
||||
if (!n) {
|
||||
printk(KERN_ERR "security: ebitmap: out of memory\n");
|
||||
rc = -ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
memset(n, 0, sizeof(*n));
|
||||
|
||||
n->startbit = le32_to_cpu(buf[0]);
|
||||
|
||||
if (n->startbit & (MAPSIZE - 1)) {
|
||||
printk(KERN_ERR "security: ebitmap start bit (%d) is "
|
||||
"not a multiple of the map size (%Zd)\n",
|
||||
n->startbit, MAPSIZE);
|
||||
goto bad_free;
|
||||
}
|
||||
if (n->startbit > (e->highbit - MAPSIZE)) {
|
||||
printk(KERN_ERR "security: ebitmap start bit (%d) is "
|
||||
"beyond the end of the bitmap (%Zd)\n",
|
||||
n->startbit, (e->highbit - MAPSIZE));
|
||||
goto bad_free;
|
||||
}
|
||||
rc = next_entry(&map, fp, sizeof(u64));
|
||||
if (rc < 0) {
|
||||
printk(KERN_ERR "security: ebitmap: truncated map\n");
|
||||
goto bad_free;
|
||||
}
|
||||
n->map = le64_to_cpu(map);
|
||||
|
||||
if (!n->map) {
|
||||
printk(KERN_ERR "security: ebitmap: null map in "
|
||||
"ebitmap (startbit %d)\n", n->startbit);
|
||||
goto bad_free;
|
||||
}
|
||||
if (l) {
|
||||
if (n->startbit <= l->startbit) {
|
||||
printk(KERN_ERR "security: ebitmap: start "
|
||||
"bit %d comes after start bit %d\n",
|
||||
n->startbit, l->startbit);
|
||||
goto bad_free;
|
||||
}
|
||||
l->next = n;
|
||||
} else
|
||||
e->node = n;
|
||||
|
||||
l = n;
|
||||
}
|
||||
|
||||
ok:
|
||||
rc = 0;
|
||||
out:
|
||||
return rc;
|
||||
bad_free:
|
||||
kfree(n);
|
||||
bad:
|
||||
if (!rc)
|
||||
rc = -EINVAL;
|
||||
ebitmap_destroy(e);
|
||||
goto out;
|
||||
}
|
48
security/selinux/ss/ebitmap.h
Normal file
48
security/selinux/ss/ebitmap.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* An extensible bitmap is a bitmap that supports an
|
||||
* arbitrary number of bits. Extensible bitmaps are
|
||||
* used to represent sets of values, such as types,
|
||||
* roles, categories, and classes.
|
||||
*
|
||||
* Each extensible bitmap is implemented as a linked
|
||||
* list of bitmap nodes, where each bitmap node has
|
||||
* an explicitly specified starting bit position within
|
||||
* the total bitmap.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_EBITMAP_H_
|
||||
#define _SS_EBITMAP_H_
|
||||
|
||||
#define MAPTYPE u64 /* portion of bitmap in each node */
|
||||
#define MAPSIZE (sizeof(MAPTYPE) * 8) /* number of bits in node bitmap */
|
||||
#define MAPBIT 1ULL /* a bit in the node bitmap */
|
||||
|
||||
struct ebitmap_node {
|
||||
u32 startbit; /* starting position in the total bitmap */
|
||||
MAPTYPE map; /* this node's portion of the bitmap */
|
||||
struct ebitmap_node *next;
|
||||
};
|
||||
|
||||
struct ebitmap {
|
||||
struct ebitmap_node *node; /* first node in the bitmap */
|
||||
u32 highbit; /* highest position in the total bitmap */
|
||||
};
|
||||
|
||||
#define ebitmap_length(e) ((e)->highbit)
|
||||
#define ebitmap_startbit(e) ((e)->node ? (e)->node->startbit : 0)
|
||||
|
||||
static inline void ebitmap_init(struct ebitmap *e)
|
||||
{
|
||||
memset(e, 0, sizeof(*e));
|
||||
}
|
||||
|
||||
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
|
||||
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
|
||||
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
|
||||
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
|
||||
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
|
||||
void ebitmap_destroy(struct ebitmap *e);
|
||||
int ebitmap_read(struct ebitmap *e, void *fp);
|
||||
|
||||
#endif /* _SS_EBITMAP_H_ */
|
167
security/selinux/ss/hashtab.c
Normal file
167
security/selinux/ss/hashtab.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Implementation of the hash table type.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#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),
|
||||
u32 size)
|
||||
{
|
||||
struct hashtab *p;
|
||||
u32 i;
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return p;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->size = size;
|
||||
p->nel = 0;
|
||||
p->hash_value = hash_value;
|
||||
p->keycmp = keycmp;
|
||||
p->htable = kmalloc(sizeof(*(p->htable)) * size, GFP_KERNEL);
|
||||
if (p->htable == NULL) {
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
p->htable[i] = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int hashtab_insert(struct hashtab *h, void *key, void *datum)
|
||||
{
|
||||
u32 hvalue;
|
||||
struct hashtab_node *prev, *cur, *newnode;
|
||||
|
||||
if (!h || h->nel == HASHTAB_MAX_NODES)
|
||||
return -EINVAL;
|
||||
|
||||
hvalue = h->hash_value(h, key);
|
||||
prev = NULL;
|
||||
cur = h->htable[hvalue];
|
||||
while (cur && h->keycmp(h, key, cur->key) > 0) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (cur && (h->keycmp(h, key, cur->key) == 0))
|
||||
return -EEXIST;
|
||||
|
||||
newnode = kmalloc(sizeof(*newnode), GFP_KERNEL);
|
||||
if (newnode == NULL)
|
||||
return -ENOMEM;
|
||||
memset(newnode, 0, sizeof(*newnode));
|
||||
newnode->key = key;
|
||||
newnode->datum = datum;
|
||||
if (prev) {
|
||||
newnode->next = prev->next;
|
||||
prev->next = newnode;
|
||||
} else {
|
||||
newnode->next = h->htable[hvalue];
|
||||
h->htable[hvalue] = newnode;
|
||||
}
|
||||
|
||||
h->nel++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *hashtab_search(struct hashtab *h, void *key)
|
||||
{
|
||||
u32 hvalue;
|
||||
struct hashtab_node *cur;
|
||||
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
hvalue = h->hash_value(h, key);
|
||||
cur = h->htable[hvalue];
|
||||
while (cur != NULL && h->keycmp(h, key, cur->key) > 0)
|
||||
cur = cur->next;
|
||||
|
||||
if (cur == NULL || (h->keycmp(h, key, cur->key) != 0))
|
||||
return NULL;
|
||||
|
||||
return cur->datum;
|
||||
}
|
||||
|
||||
void hashtab_destroy(struct hashtab *h)
|
||||
{
|
||||
u32 i;
|
||||
struct hashtab_node *cur, *temp;
|
||||
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
for (i = 0; i < h->size; i++) {
|
||||
cur = h->htable[i];
|
||||
while (cur != NULL) {
|
||||
temp = cur;
|
||||
cur = cur->next;
|
||||
kfree(temp);
|
||||
}
|
||||
h->htable[i] = NULL;
|
||||
}
|
||||
|
||||
kfree(h->htable);
|
||||
h->htable = NULL;
|
||||
|
||||
kfree(h);
|
||||
}
|
||||
|
||||
int hashtab_map(struct hashtab *h,
|
||||
int (*apply)(void *k, void *d, void *args),
|
||||
void *args)
|
||||
{
|
||||
u32 i;
|
||||
int ret;
|
||||
struct hashtab_node *cur;
|
||||
|
||||
if (!h)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < h->size; i++) {
|
||||
cur = h->htable[i];
|
||||
while (cur != NULL) {
|
||||
ret = apply(cur->key, cur->datum, args);
|
||||
if (ret)
|
||||
return ret;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
|
||||
{
|
||||
u32 i, chain_len, slots_used, max_chain_len;
|
||||
struct hashtab_node *cur;
|
||||
|
||||
slots_used = 0;
|
||||
max_chain_len = 0;
|
||||
for (slots_used = max_chain_len = i = 0; i < h->size; i++) {
|
||||
cur = h->htable[i];
|
||||
if (cur) {
|
||||
slots_used++;
|
||||
chain_len = 0;
|
||||
while (cur) {
|
||||
chain_len++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (chain_len > max_chain_len)
|
||||
max_chain_len = chain_len;
|
||||
}
|
||||
}
|
||||
|
||||
info->slots_used = slots_used;
|
||||
info->max_chain_len = max_chain_len;
|
||||
}
|
87
security/selinux/ss/hashtab.h
Normal file
87
security/selinux/ss/hashtab.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* A hash table (hashtab) maintains associations between
|
||||
* key values and datum values. The type of the key values
|
||||
* and the type of the datum values is arbitrary. The
|
||||
* functions for hash computation and key comparison are
|
||||
* provided by the creator of the table.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_HASHTAB_H_
|
||||
#define _SS_HASHTAB_H_
|
||||
|
||||
#define HASHTAB_MAX_NODES 0xffffffff
|
||||
|
||||
struct hashtab_node {
|
||||
void *key;
|
||||
void *datum;
|
||||
struct hashtab_node *next;
|
||||
};
|
||||
|
||||
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);
|
||||
/* hash function */
|
||||
int (*keycmp)(struct hashtab *h, void *key1, void *key2);
|
||||
/* key comparison function */
|
||||
};
|
||||
|
||||
struct hashtab_info {
|
||||
u32 slots_used;
|
||||
u32 max_chain_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* Creates a new hash table with the specified characteristics.
|
||||
*
|
||||
* 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),
|
||||
u32 size);
|
||||
|
||||
/*
|
||||
* Inserts the specified (key, datum) pair into the specified hash table.
|
||||
*
|
||||
* Returns -ENOMEM on memory allocation error,
|
||||
* -EEXIST if there is already an entry with the same key,
|
||||
* -EINVAL for general errors or
|
||||
* 0 otherwise.
|
||||
*/
|
||||
int hashtab_insert(struct hashtab *h, void *k, void *d);
|
||||
|
||||
/*
|
||||
* Searches for the entry with the specified key in the hash table.
|
||||
*
|
||||
* Returns NULL if no entry has the specified key or
|
||||
* the datum of the entry otherwise.
|
||||
*/
|
||||
void *hashtab_search(struct hashtab *h, void *k);
|
||||
|
||||
/*
|
||||
* Destroys the specified hash table.
|
||||
*/
|
||||
void hashtab_destroy(struct hashtab *h);
|
||||
|
||||
/*
|
||||
* Applies the specified apply function to (key,datum,args)
|
||||
* for each entry in the specified hash table.
|
||||
*
|
||||
* The order in which the function is applied to the entries
|
||||
* is dependent upon the internal structure of the hash table.
|
||||
*
|
||||
* If apply returns a non-zero status, then hashtab_map will cease
|
||||
* iterating through the hash table and will propagate the error
|
||||
* return to its caller.
|
||||
*/
|
||||
int hashtab_map(struct hashtab *h,
|
||||
int (*apply)(void *k, void *d, void *args),
|
||||
void *args);
|
||||
|
||||
/* Fill info with some hash table statistics */
|
||||
void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
|
||||
|
||||
#endif /* _SS_HASHTAB_H */
|
527
security/selinux/ss/mls.c
Normal file
527
security/selinux/ss/mls.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Implementation of the multi-level security (MLS) policy.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
/*
|
||||
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
||||
*
|
||||
* Support for enhanced MLS infrastructure.
|
||||
*
|
||||
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include "mls.h"
|
||||
#include "policydb.h"
|
||||
#include "services.h"
|
||||
|
||||
/*
|
||||
* Return the length in bytes for the MLS fields of the
|
||||
* security context string representation of `context'.
|
||||
*/
|
||||
int mls_compute_context_len(struct context * context)
|
||||
{
|
||||
int i, l, len, range;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
len = 1; /* for the beginning ":" */
|
||||
for (l = 0; l < 2; l++) {
|
||||
range = 0;
|
||||
len += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
|
||||
|
||||
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
|
||||
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
|
||||
if (range) {
|
||||
range++;
|
||||
continue;
|
||||
}
|
||||
|
||||
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 1;
|
||||
range++;
|
||||
} else {
|
||||
if (range > 1)
|
||||
len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
|
||||
range = 0;
|
||||
}
|
||||
}
|
||||
/* Handle case where last category is the end of range */
|
||||
if (range > 1)
|
||||
len += strlen(policydb.p_cat_val_to_name[i - 2]) + 1;
|
||||
|
||||
if (l == 0) {
|
||||
if (mls_level_eq(&context->range.level[0],
|
||||
&context->range.level[1]))
|
||||
break;
|
||||
else
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the security context string representation of
|
||||
* the MLS fields of `context' into the string `*scontext'.
|
||||
* Update `*scontext' to point to the end of the MLS fields.
|
||||
*/
|
||||
void mls_sid_to_context(struct context *context,
|
||||
char **scontext)
|
||||
{
|
||||
char *scontextp;
|
||||
int i, l, range, wrote_sep;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return;
|
||||
|
||||
scontextp = *scontext;
|
||||
|
||||
*scontextp = ':';
|
||||
scontextp++;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
range = 0;
|
||||
wrote_sep = 0;
|
||||
strcpy(scontextp,
|
||||
policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
|
||||
scontextp += strlen(policydb.p_sens_val_to_name[context->range.level[l].sens - 1]);
|
||||
|
||||
/* categories */
|
||||
for (i = 1; i <= ebitmap_length(&context->range.level[l].cat); i++) {
|
||||
if (ebitmap_get_bit(&context->range.level[l].cat, i - 1)) {
|
||||
if (range) {
|
||||
range++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!wrote_sep) {
|
||||
*scontextp++ = ':';
|
||||
wrote_sep = 1;
|
||||
} else
|
||||
*scontextp++ = ',';
|
||||
strcpy(scontextp, policydb.p_cat_val_to_name[i - 1]);
|
||||
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
|
||||
range++;
|
||||
} else {
|
||||
if (range > 1) {
|
||||
if (range > 2)
|
||||
*scontextp++ = '.';
|
||||
else
|
||||
*scontextp++ = ',';
|
||||
|
||||
strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
|
||||
scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
|
||||
}
|
||||
range = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle case where last category is the end of range */
|
||||
if (range > 1) {
|
||||
if (range > 2)
|
||||
*scontextp++ = '.';
|
||||
else
|
||||
*scontextp++ = ',';
|
||||
|
||||
strcpy(scontextp, policydb.p_cat_val_to_name[i - 2]);
|
||||
scontextp += strlen(policydb.p_cat_val_to_name[i - 2]);
|
||||
}
|
||||
|
||||
if (l == 0) {
|
||||
if (mls_level_eq(&context->range.level[0],
|
||||
&context->range.level[1]))
|
||||
break;
|
||||
else {
|
||||
*scontextp = '-';
|
||||
scontextp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*scontext = scontextp;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 if the MLS fields in the security context
|
||||
* structure `c' are valid. Return 0 otherwise.
|
||||
*/
|
||||
int mls_context_isvalid(struct policydb *p, struct context *c)
|
||||
{
|
||||
struct level_datum *levdatum;
|
||||
struct user_datum *usrdatum;
|
||||
int i, l;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* MLS range validity checks: high must dominate low, low level must
|
||||
* be valid (category set <-> sensitivity check), and high level must
|
||||
* be valid (category set <-> sensitivity check)
|
||||
*/
|
||||
if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
|
||||
/* High does not dominate low. */
|
||||
return 0;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
|
||||
return 0;
|
||||
levdatum = hashtab_search(p->p_levels.table,
|
||||
p->p_sens_val_to_name[c->range.level[l].sens - 1]);
|
||||
if (!levdatum)
|
||||
return 0;
|
||||
|
||||
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
|
||||
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
|
||||
if (i > p->p_cats.nprim)
|
||||
return 0;
|
||||
if (!ebitmap_get_bit(&levdatum->level->cat, i - 1))
|
||||
/*
|
||||
* Category may not be associated with
|
||||
* sensitivity in low level.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c->role == OBJECT_R_VAL)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* User must be authorized for the MLS range.
|
||||
*/
|
||||
if (!c->user || c->user > p->p_users.nprim)
|
||||
return 0;
|
||||
usrdatum = p->user_val_to_struct[c->user - 1];
|
||||
if (!mls_range_contains(usrdatum->range, c->range))
|
||||
return 0; /* user may not be associated with range */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the MLS fields in the security context structure
|
||||
* `context' based on the string representation in
|
||||
* the string `*scontext'. Update `*scontext' to
|
||||
* point to the end of the string representation of
|
||||
* the MLS fields.
|
||||
*
|
||||
* This function modifies the string in place, inserting
|
||||
* NULL characters to terminate the MLS fields.
|
||||
*/
|
||||
int mls_context_to_sid(char oldc,
|
||||
char **scontext,
|
||||
struct context *context)
|
||||
{
|
||||
|
||||
char delim;
|
||||
char *scontextp, *p, *rngptr;
|
||||
struct level_datum *levdatum;
|
||||
struct cat_datum *catdatum, *rngdatum;
|
||||
int l, rc = -EINVAL;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
/* No MLS component to the security context. */
|
||||
if (!oldc)
|
||||
goto out;
|
||||
|
||||
/* Extract low sensitivity. */
|
||||
scontextp = p = *scontext;
|
||||
while (*p && *p != ':' && *p != '-')
|
||||
p++;
|
||||
|
||||
delim = *p;
|
||||
if (delim != 0)
|
||||
*p++ = 0;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
levdatum = hashtab_search(policydb.p_levels.table, scontextp);
|
||||
if (!levdatum) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
context->range.level[l].sens = levdatum->level->sens;
|
||||
|
||||
if (delim == ':') {
|
||||
/* Extract category set. */
|
||||
while (1) {
|
||||
scontextp = p;
|
||||
while (*p && *p != ',' && *p != '-')
|
||||
p++;
|
||||
delim = *p;
|
||||
if (delim != 0)
|
||||
*p++ = 0;
|
||||
|
||||
/* Separate into range if exists */
|
||||
if ((rngptr = strchr(scontextp, '.')) != NULL) {
|
||||
/* Remove '.' */
|
||||
*rngptr++ = 0;
|
||||
}
|
||||
|
||||
catdatum = hashtab_search(policydb.p_cats.table,
|
||||
scontextp);
|
||||
if (!catdatum) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ebitmap_set_bit(&context->range.level[l].cat,
|
||||
catdatum->value - 1, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
/* If range, set all categories in range */
|
||||
if (rngptr) {
|
||||
int i;
|
||||
|
||||
rngdatum = hashtab_search(policydb.p_cats.table, rngptr);
|
||||
if (!rngdatum) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (catdatum->value >= rngdatum->value) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = catdatum->value; i < rngdatum->value; i++) {
|
||||
rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (delim != ',')
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (delim == '-') {
|
||||
/* Extract high sensitivity. */
|
||||
scontextp = p;
|
||||
while (*p && *p != ':')
|
||||
p++;
|
||||
|
||||
delim = *p;
|
||||
if (delim != 0)
|
||||
*p++ = 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (l == 0) {
|
||||
context->range.level[1].sens = context->range.level[0].sens;
|
||||
rc = ebitmap_cpy(&context->range.level[1].cat,
|
||||
&context->range.level[0].cat);
|
||||
if (rc)
|
||||
goto out;
|
||||
}
|
||||
*scontext = ++p;
|
||||
rc = 0;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies the MLS range from `src' into `dst'.
|
||||
*/
|
||||
static inline int mls_copy_context(struct context *dst,
|
||||
struct context *src)
|
||||
{
|
||||
int l, rc = 0;
|
||||
|
||||
/* Copy the MLS range from the source context */
|
||||
for (l = 0; l < 2; l++) {
|
||||
dst->range.level[l].sens = src->range.level[l].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[l].cat,
|
||||
&src->range.level[l].cat);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies the effective MLS range from `src' into `dst'.
|
||||
*/
|
||||
static inline int mls_scopy_context(struct context *dst,
|
||||
struct context *src)
|
||||
{
|
||||
int l, rc = 0;
|
||||
|
||||
/* Copy the MLS range from the source context */
|
||||
for (l = 0; l < 2; l++) {
|
||||
dst->range.level[l].sens = src->range.level[0].sens;
|
||||
rc = ebitmap_cpy(&dst->range.level[l].cat,
|
||||
&src->range.level[0].cat);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies the MLS range `range' into `context'.
|
||||
*/
|
||||
static inline int mls_range_set(struct context *context,
|
||||
struct mls_range *range)
|
||||
{
|
||||
int l, rc = 0;
|
||||
|
||||
/* Copy the MLS range into the context */
|
||||
for (l = 0; l < 2; l++) {
|
||||
context->range.level[l].sens = range->level[l].sens;
|
||||
rc = ebitmap_cpy(&context->range.level[l].cat,
|
||||
&range->level[l].cat);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
|
||||
struct context *usercon)
|
||||
{
|
||||
if (selinux_mls_enabled) {
|
||||
struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
|
||||
struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
|
||||
struct mls_level *user_low = &(user->range.level[0]);
|
||||
struct mls_level *user_clr = &(user->range.level[1]);
|
||||
struct mls_level *user_def = &(user->dfltlevel);
|
||||
struct mls_level *usercon_sen = &(usercon->range.level[0]);
|
||||
struct mls_level *usercon_clr = &(usercon->range.level[1]);
|
||||
|
||||
/* Honor the user's default level if we can */
|
||||
if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
|
||||
*usercon_sen = *user_def;
|
||||
} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
|
||||
*usercon_sen = *fromcon_sen;
|
||||
} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
|
||||
*usercon_sen = *user_low;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
/* Lower the clearance of available contexts
|
||||
if the clearance of "fromcon" is lower than
|
||||
that of the user's default clearance (but
|
||||
only if the "fromcon" clearance dominates
|
||||
the user's computed sensitivity level) */
|
||||
if (mls_level_dom(user_clr, fromcon_clr)) {
|
||||
*usercon_clr = *fromcon_clr;
|
||||
} else if (mls_level_dom(fromcon_clr, user_clr)) {
|
||||
*usercon_clr = *user_clr;
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the MLS fields in the security context
|
||||
* structure `c' from the values specified in the
|
||||
* policy `oldp' to the values specified in the policy `newp'.
|
||||
*/
|
||||
int mls_convert_context(struct policydb *oldp,
|
||||
struct policydb *newp,
|
||||
struct context *c)
|
||||
{
|
||||
struct level_datum *levdatum;
|
||||
struct cat_datum *catdatum;
|
||||
struct ebitmap bitmap;
|
||||
int l, i;
|
||||
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
for (l = 0; l < 2; l++) {
|
||||
levdatum = hashtab_search(newp->p_levels.table,
|
||||
oldp->p_sens_val_to_name[c->range.level[l].sens - 1]);
|
||||
|
||||
if (!levdatum)
|
||||
return -EINVAL;
|
||||
c->range.level[l].sens = levdatum->level->sens;
|
||||
|
||||
ebitmap_init(&bitmap);
|
||||
for (i = 1; i <= ebitmap_length(&c->range.level[l].cat); i++) {
|
||||
if (ebitmap_get_bit(&c->range.level[l].cat, i - 1)) {
|
||||
int rc;
|
||||
|
||||
catdatum = hashtab_search(newp->p_cats.table,
|
||||
oldp->p_cat_val_to_name[i - 1]);
|
||||
if (!catdatum)
|
||||
return -EINVAL;
|
||||
rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
ebitmap_destroy(&c->range.level[l].cat);
|
||||
c->range.level[l].cat = bitmap;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mls_compute_sid(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
u32 specified,
|
||||
struct context *newcontext)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 0;
|
||||
|
||||
switch (specified) {
|
||||
case AVTAB_TRANSITION:
|
||||
if (tclass == SECCLASS_PROCESS) {
|
||||
struct range_trans *rangetr;
|
||||
/* Look for a range transition rule. */
|
||||
for (rangetr = policydb.range_tr; rangetr;
|
||||
rangetr = rangetr->next) {
|
||||
if (rangetr->dom == scontext->type &&
|
||||
rangetr->type == tcontext->type) {
|
||||
/* Set the range from the rule */
|
||||
return mls_range_set(newcontext,
|
||||
&rangetr->range);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Fallthrough */
|
||||
case AVTAB_CHANGE:
|
||||
if (tclass == SECCLASS_PROCESS)
|
||||
/* Use the process MLS attributes. */
|
||||
return mls_copy_context(newcontext, scontext);
|
||||
else
|
||||
/* Use the process effective MLS attributes. */
|
||||
return mls_scopy_context(newcontext, scontext);
|
||||
case AVTAB_MEMBER:
|
||||
/* Only polyinstantiate the MLS attributes if
|
||||
the type is being polyinstantiated */
|
||||
if (newcontext->type != tcontext->type) {
|
||||
/* Use the process effective MLS attributes. */
|
||||
return mls_scopy_context(newcontext, scontext);
|
||||
} else {
|
||||
/* Use the related object MLS attributes. */
|
||||
return mls_copy_context(newcontext, tcontext);
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
42
security/selinux/ss/mls.h
Normal file
42
security/selinux/ss/mls.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Multi-level security (MLS) policy operations.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
/*
|
||||
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
||||
*
|
||||
* Support for enhanced MLS infrastructure.
|
||||
*
|
||||
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SS_MLS_H_
|
||||
#define _SS_MLS_H_
|
||||
|
||||
#include "context.h"
|
||||
#include "policydb.h"
|
||||
|
||||
int mls_compute_context_len(struct context *context);
|
||||
void mls_sid_to_context(struct context *context, char **scontext);
|
||||
int mls_context_isvalid(struct policydb *p, struct context *c);
|
||||
|
||||
int mls_context_to_sid(char oldc,
|
||||
char **scontext,
|
||||
struct context *context);
|
||||
|
||||
int mls_convert_context(struct policydb *oldp,
|
||||
struct policydb *newp,
|
||||
struct context *context);
|
||||
|
||||
int mls_compute_sid(struct context *scontext,
|
||||
struct context *tcontext,
|
||||
u16 tclass,
|
||||
u32 specified,
|
||||
struct context *newcontext);
|
||||
|
||||
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
|
||||
struct context *usercon);
|
||||
|
||||
#endif /* _SS_MLS_H */
|
||||
|
56
security/selinux/ss/mls_types.h
Normal file
56
security/selinux/ss/mls_types.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Type definitions for the multi-level security (MLS) policy.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
/*
|
||||
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
||||
*
|
||||
* Support for enhanced MLS infrastructure.
|
||||
*
|
||||
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SS_MLS_TYPES_H_
|
||||
#define _SS_MLS_TYPES_H_
|
||||
|
||||
#include "security.h"
|
||||
|
||||
struct mls_level {
|
||||
u32 sens; /* sensitivity */
|
||||
struct ebitmap cat; /* category set */
|
||||
};
|
||||
|
||||
struct mls_range {
|
||||
struct mls_level level[2]; /* low == level[0], high == level[1] */
|
||||
};
|
||||
|
||||
static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((l1->sens == l2->sens) &&
|
||||
ebitmap_cmp(&l1->cat, &l2->cat));
|
||||
}
|
||||
|
||||
static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
|
||||
{
|
||||
if (!selinux_mls_enabled)
|
||||
return 1;
|
||||
|
||||
return ((l1->sens >= l2->sens) &&
|
||||
ebitmap_contains(&l1->cat, &l2->cat));
|
||||
}
|
||||
|
||||
#define mls_level_incomp(l1, l2) \
|
||||
(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
|
||||
|
||||
#define mls_level_between(l1, l2, l3) \
|
||||
(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
|
||||
|
||||
#define mls_range_contains(r1, r2) \
|
||||
(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
|
||||
mls_level_dom(&(r1).level[1], &(r2).level[1]))
|
||||
|
||||
#endif /* _SS_MLS_TYPES_H_ */
|
1843
security/selinux/ss/policydb.c
Normal file
1843
security/selinux/ss/policydb.c
Normal file
File diff suppressed because it is too large
Load Diff
275
security/selinux/ss/policydb.h
Normal file
275
security/selinux/ss/policydb.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* A policy database (policydb) specifies the
|
||||
* configuration data for the security policy.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
|
||||
*
|
||||
* Support for enhanced MLS infrastructure.
|
||||
*
|
||||
* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
||||
*
|
||||
* Added conditional policy language extensions
|
||||
*
|
||||
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
||||
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
|
||||
* 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
|
||||
* the Free Software Foundation, version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SS_POLICYDB_H_
|
||||
#define _SS_POLICYDB_H_
|
||||
|
||||
#include "symtab.h"
|
||||
#include "avtab.h"
|
||||
#include "sidtab.h"
|
||||
#include "context.h"
|
||||
#include "constraint.h"
|
||||
|
||||
/*
|
||||
* A datum type is defined for each kind of symbol
|
||||
* in the configuration data: individual permissions,
|
||||
* common prefixes for access vectors, classes,
|
||||
* users, roles, types, sensitivities, categories, etc.
|
||||
*/
|
||||
|
||||
/* Permission attributes */
|
||||
struct perm_datum {
|
||||
u32 value; /* permission bit + 1 */
|
||||
};
|
||||
|
||||
/* Attributes of a common prefix for access vectors */
|
||||
struct common_datum {
|
||||
u32 value; /* internal common value */
|
||||
struct symtab permissions; /* common permissions */
|
||||
};
|
||||
|
||||
/* Class attributes */
|
||||
struct class_datum {
|
||||
u32 value; /* class value */
|
||||
char *comkey; /* common name */
|
||||
struct common_datum *comdatum; /* common datum */
|
||||
struct symtab permissions; /* class-specific permission symbol table */
|
||||
struct constraint_node *constraints; /* constraints on class permissions */
|
||||
struct constraint_node *validatetrans; /* special transition rules */
|
||||
};
|
||||
|
||||
/* Role attributes */
|
||||
struct role_datum {
|
||||
u32 value; /* internal role value */
|
||||
struct ebitmap dominates; /* set of roles dominated by this role */
|
||||
struct ebitmap types; /* set of authorized types for role */
|
||||
};
|
||||
|
||||
struct role_trans {
|
||||
u32 role; /* current role */
|
||||
u32 type; /* program executable type */
|
||||
u32 new_role; /* new role */
|
||||
struct role_trans *next;
|
||||
};
|
||||
|
||||
struct role_allow {
|
||||
u32 role; /* current role */
|
||||
u32 new_role; /* new role */
|
||||
struct role_allow *next;
|
||||
};
|
||||
|
||||
/* Type attributes */
|
||||
struct type_datum {
|
||||
u32 value; /* internal type value */
|
||||
unsigned char primary; /* primary name? */
|
||||
};
|
||||
|
||||
/* User attributes */
|
||||
struct user_datum {
|
||||
u32 value; /* internal user value */
|
||||
struct ebitmap roles; /* set of authorized roles for user */
|
||||
struct mls_range range; /* MLS range (min - max) for user */
|
||||
struct mls_level dfltlevel; /* default login MLS level for user */
|
||||
};
|
||||
|
||||
|
||||
/* Sensitivity attributes */
|
||||
struct level_datum {
|
||||
struct mls_level *level; /* sensitivity and associated categories */
|
||||
unsigned char isalias; /* is this sensitivity an alias for another? */
|
||||
};
|
||||
|
||||
/* Category attributes */
|
||||
struct cat_datum {
|
||||
u32 value; /* internal category bit + 1 */
|
||||
unsigned char isalias; /* is this category an alias for another? */
|
||||
};
|
||||
|
||||
struct range_trans {
|
||||
u32 dom; /* current process domain */
|
||||
u32 type; /* program executable type */
|
||||
struct mls_range range; /* new range */
|
||||
struct range_trans *next;
|
||||
};
|
||||
|
||||
/* Boolean data type */
|
||||
struct cond_bool_datum {
|
||||
__u32 value; /* internal type value */
|
||||
int state;
|
||||
};
|
||||
|
||||
struct cond_node;
|
||||
|
||||
/*
|
||||
* The configuration data includes security contexts for
|
||||
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
|
||||
* network interfaces, and nodes. This structure stores the
|
||||
* relevant data for one such entry. Entries of the same kind
|
||||
* (e.g. all initial SIDs) are linked together into a list.
|
||||
*/
|
||||
struct ocontext {
|
||||
union {
|
||||
char *name; /* name of initial SID, fs, netif, fstype, path */
|
||||
struct {
|
||||
u8 protocol;
|
||||
u16 low_port;
|
||||
u16 high_port;
|
||||
} port; /* TCP or UDP port information */
|
||||
struct {
|
||||
u32 addr;
|
||||
u32 mask;
|
||||
} node; /* node information */
|
||||
struct {
|
||||
u32 addr[4];
|
||||
u32 mask[4];
|
||||
} node6; /* IPv6 node information */
|
||||
} u;
|
||||
union {
|
||||
u32 sclass; /* security class for genfs */
|
||||
u32 behavior; /* labeling behavior for fs_use */
|
||||
} v;
|
||||
struct context context[2]; /* security context(s) */
|
||||
u32 sid[2]; /* SID(s) */
|
||||
struct ocontext *next;
|
||||
};
|
||||
|
||||
struct genfs {
|
||||
char *fstype;
|
||||
struct ocontext *head;
|
||||
struct genfs *next;
|
||||
};
|
||||
|
||||
/* symbol table array indices */
|
||||
#define SYM_COMMONS 0
|
||||
#define SYM_CLASSES 1
|
||||
#define SYM_ROLES 2
|
||||
#define SYM_TYPES 3
|
||||
#define SYM_USERS 4
|
||||
#define SYM_BOOLS 5
|
||||
#define SYM_LEVELS 6
|
||||
#define SYM_CATS 7
|
||||
#define SYM_NUM 8
|
||||
|
||||
/* object context array indices */
|
||||
#define OCON_ISID 0 /* initial SIDs */
|
||||
#define OCON_FS 1 /* unlabeled file systems */
|
||||
#define OCON_PORT 2 /* TCP and UDP port numbers */
|
||||
#define OCON_NETIF 3 /* network interfaces */
|
||||
#define OCON_NODE 4 /* nodes */
|
||||
#define OCON_FSUSE 5 /* fs_use */
|
||||
#define OCON_NODE6 6 /* IPv6 nodes */
|
||||
#define OCON_NUM 7
|
||||
|
||||
/* The policy database */
|
||||
struct policydb {
|
||||
/* symbol tables */
|
||||
struct symtab symtab[SYM_NUM];
|
||||
#define p_commons symtab[SYM_COMMONS]
|
||||
#define p_classes symtab[SYM_CLASSES]
|
||||
#define p_roles symtab[SYM_ROLES]
|
||||
#define p_types symtab[SYM_TYPES]
|
||||
#define p_users symtab[SYM_USERS]
|
||||
#define p_bools symtab[SYM_BOOLS]
|
||||
#define p_levels symtab[SYM_LEVELS]
|
||||
#define p_cats symtab[SYM_CATS]
|
||||
|
||||
/* symbol names indexed by (value - 1) */
|
||||
char **sym_val_to_name[SYM_NUM];
|
||||
#define p_common_val_to_name sym_val_to_name[SYM_COMMONS]
|
||||
#define p_class_val_to_name sym_val_to_name[SYM_CLASSES]
|
||||
#define p_role_val_to_name sym_val_to_name[SYM_ROLES]
|
||||
#define p_type_val_to_name sym_val_to_name[SYM_TYPES]
|
||||
#define p_user_val_to_name sym_val_to_name[SYM_USERS]
|
||||
#define p_bool_val_to_name sym_val_to_name[SYM_BOOLS]
|
||||
#define p_sens_val_to_name sym_val_to_name[SYM_LEVELS]
|
||||
#define p_cat_val_to_name sym_val_to_name[SYM_CATS]
|
||||
|
||||
/* class, role, and user attributes indexed by (value - 1) */
|
||||
struct class_datum **class_val_to_struct;
|
||||
struct role_datum **role_val_to_struct;
|
||||
struct user_datum **user_val_to_struct;
|
||||
|
||||
/* type enforcement access vectors and transitions */
|
||||
struct avtab te_avtab;
|
||||
|
||||
/* role transitions */
|
||||
struct role_trans *role_tr;
|
||||
|
||||
/* bools indexed by (value - 1) */
|
||||
struct cond_bool_datum **bool_val_to_struct;
|
||||
/* type enforcement conditional access vectors and transitions */
|
||||
struct avtab te_cond_avtab;
|
||||
/* linked list indexing te_cond_avtab by conditional */
|
||||
struct cond_node* cond_list;
|
||||
|
||||
/* role allows */
|
||||
struct role_allow *role_allow;
|
||||
|
||||
/* security contexts of initial SIDs, unlabeled file systems,
|
||||
TCP or UDP port numbers, network interfaces and nodes */
|
||||
struct ocontext *ocontexts[OCON_NUM];
|
||||
|
||||
/* security contexts for files in filesystems that cannot support
|
||||
a persistent label mapping or use another
|
||||
fixed labeling behavior. */
|
||||
struct genfs *genfs;
|
||||
|
||||
/* range transitions */
|
||||
struct range_trans *range_tr;
|
||||
|
||||
unsigned int policyvers;
|
||||
};
|
||||
|
||||
extern void policydb_destroy(struct policydb *p);
|
||||
extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
|
||||
extern int policydb_context_isvalid(struct policydb *p, struct context *c);
|
||||
extern int policydb_read(struct policydb *p, void *fp);
|
||||
|
||||
#define PERM_SYMTAB_SIZE 32
|
||||
|
||||
#define POLICYDB_CONFIG_MLS 1
|
||||
|
||||
#define OBJECT_R "object_r"
|
||||
#define OBJECT_R_VAL 1
|
||||
|
||||
#define POLICYDB_MAGIC SELINUX_MAGIC
|
||||
#define POLICYDB_STRING "SE Linux"
|
||||
|
||||
struct policy_file {
|
||||
char *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
|
||||
{
|
||||
if (bytes > fp->len)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buf, fp->data, bytes);
|
||||
fp->data += bytes;
|
||||
fp->len -= bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _SS_POLICYDB_H_ */
|
||||
|
1777
security/selinux/ss/services.c
Normal file
1777
security/selinux/ss/services.c
Normal file
File diff suppressed because it is too large
Load Diff
15
security/selinux/ss/services.h
Normal file
15
security/selinux/ss/services.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Implementation of the security services.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_SERVICES_H_
|
||||
#define _SS_SERVICES_H_
|
||||
|
||||
#include "policydb.h"
|
||||
#include "sidtab.h"
|
||||
|
||||
extern struct policydb policydb;
|
||||
|
||||
#endif /* _SS_SERVICES_H_ */
|
||||
|
305
security/selinux/ss/sidtab.c
Normal file
305
security/selinux/ss/sidtab.c
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Implementation of the SID table type.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include "flask.h"
|
||||
#include "security.h"
|
||||
#include "sidtab.h"
|
||||
|
||||
#define SIDTAB_HASH(sid) \
|
||||
(sid & SIDTAB_HASH_MASK)
|
||||
|
||||
#define INIT_SIDTAB_LOCK(s) spin_lock_init(&s->lock)
|
||||
#define SIDTAB_LOCK(s, x) spin_lock_irqsave(&s->lock, x)
|
||||
#define SIDTAB_UNLOCK(s, x) spin_unlock_irqrestore(&s->lock, x)
|
||||
|
||||
int sidtab_init(struct sidtab *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
s->htable = kmalloc(sizeof(*(s->htable)) * SIDTAB_SIZE, GFP_ATOMIC);
|
||||
if (!s->htable)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < SIDTAB_SIZE; i++)
|
||||
s->htable[i] = NULL;
|
||||
s->nel = 0;
|
||||
s->next_sid = 1;
|
||||
s->shutdown = 0;
|
||||
INIT_SIDTAB_LOCK(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context)
|
||||
{
|
||||
int hvalue, rc = 0;
|
||||
struct sidtab_node *prev, *cur, *newnode;
|
||||
|
||||
if (!s) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hvalue = SIDTAB_HASH(sid);
|
||||
prev = NULL;
|
||||
cur = s->htable[hvalue];
|
||||
while (cur != NULL && sid > cur->sid) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (cur && sid == cur->sid) {
|
||||
rc = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
newnode = kmalloc(sizeof(*newnode), GFP_ATOMIC);
|
||||
if (newnode == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
newnode->sid = sid;
|
||||
if (context_cpy(&newnode->context, context)) {
|
||||
kfree(newnode);
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
newnode->next = prev->next;
|
||||
wmb();
|
||||
prev->next = newnode;
|
||||
} else {
|
||||
newnode->next = s->htable[hvalue];
|
||||
wmb();
|
||||
s->htable[hvalue] = newnode;
|
||||
}
|
||||
|
||||
s->nel++;
|
||||
if (sid >= s->next_sid)
|
||||
s->next_sid = sid + 1;
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct context *sidtab_search(struct sidtab *s, u32 sid)
|
||||
{
|
||||
int hvalue;
|
||||
struct sidtab_node *cur;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
hvalue = SIDTAB_HASH(sid);
|
||||
cur = s->htable[hvalue];
|
||||
while (cur != NULL && sid > cur->sid)
|
||||
cur = cur->next;
|
||||
|
||||
if (cur == NULL || sid != cur->sid) {
|
||||
/* Remap invalid SIDs to the unlabeled SID. */
|
||||
sid = SECINITSID_UNLABELED;
|
||||
hvalue = SIDTAB_HASH(sid);
|
||||
cur = s->htable[hvalue];
|
||||
while (cur != NULL && sid > cur->sid)
|
||||
cur = cur->next;
|
||||
if (!cur || sid != cur->sid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cur->context;
|
||||
}
|
||||
|
||||
int sidtab_map(struct sidtab *s,
|
||||
int (*apply) (u32 sid,
|
||||
struct context *context,
|
||||
void *args),
|
||||
void *args)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct sidtab_node *cur;
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
cur = s->htable[i];
|
||||
while (cur != NULL) {
|
||||
rc = apply(cur->sid, &cur->context, args);
|
||||
if (rc)
|
||||
goto out;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sidtab_map_remove_on_error(struct sidtab *s,
|
||||
int (*apply) (u32 sid,
|
||||
struct context *context,
|
||||
void *args),
|
||||
void *args)
|
||||
{
|
||||
int i, ret;
|
||||
struct sidtab_node *last, *cur, *temp;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
last = NULL;
|
||||
cur = s->htable[i];
|
||||
while (cur != NULL) {
|
||||
ret = apply(cur->sid, &cur->context, args);
|
||||
if (ret) {
|
||||
if (last) {
|
||||
last->next = cur->next;
|
||||
} else {
|
||||
s->htable[i] = cur->next;
|
||||
}
|
||||
|
||||
temp = cur;
|
||||
cur = cur->next;
|
||||
context_destroy(&temp->context);
|
||||
kfree(temp);
|
||||
s->nel--;
|
||||
} else {
|
||||
last = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u32 sidtab_search_context(struct sidtab *s,
|
||||
struct context *context)
|
||||
{
|
||||
int i;
|
||||
struct sidtab_node *cur;
|
||||
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
cur = s->htable[i];
|
||||
while (cur != NULL) {
|
||||
if (context_cmp(&cur->context, context))
|
||||
return cur->sid;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sidtab_context_to_sid(struct sidtab *s,
|
||||
struct context *context,
|
||||
u32 *out_sid)
|
||||
{
|
||||
u32 sid;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
*out_sid = SECSID_NULL;
|
||||
|
||||
sid = sidtab_search_context(s, context);
|
||||
if (!sid) {
|
||||
SIDTAB_LOCK(s, flags);
|
||||
/* Rescan now that we hold the lock. */
|
||||
sid = sidtab_search_context(s, context);
|
||||
if (sid)
|
||||
goto unlock_out;
|
||||
/* No SID exists for the context. Allocate a new one. */
|
||||
if (s->next_sid == UINT_MAX || s->shutdown) {
|
||||
ret = -ENOMEM;
|
||||
goto unlock_out;
|
||||
}
|
||||
sid = s->next_sid++;
|
||||
ret = sidtab_insert(s, sid, context);
|
||||
if (ret)
|
||||
s->next_sid--;
|
||||
unlock_out:
|
||||
SIDTAB_UNLOCK(s, flags);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*out_sid = sid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sidtab_hash_eval(struct sidtab *h, char *tag)
|
||||
{
|
||||
int i, chain_len, slots_used, max_chain_len;
|
||||
struct sidtab_node *cur;
|
||||
|
||||
slots_used = 0;
|
||||
max_chain_len = 0;
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
cur = h->htable[i];
|
||||
if (cur) {
|
||||
slots_used++;
|
||||
chain_len = 0;
|
||||
while (cur) {
|
||||
chain_len++;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (chain_len > max_chain_len)
|
||||
max_chain_len = chain_len;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: %d entries and %d/%d buckets used, longest "
|
||||
"chain length %d\n", tag, h->nel, slots_used, SIDTAB_SIZE,
|
||||
max_chain_len);
|
||||
}
|
||||
|
||||
void sidtab_destroy(struct sidtab *s)
|
||||
{
|
||||
int i;
|
||||
struct sidtab_node *cur, *temp;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
for (i = 0; i < SIDTAB_SIZE; i++) {
|
||||
cur = s->htable[i];
|
||||
while (cur != NULL) {
|
||||
temp = cur;
|
||||
cur = cur->next;
|
||||
context_destroy(&temp->context);
|
||||
kfree(temp);
|
||||
}
|
||||
s->htable[i] = NULL;
|
||||
}
|
||||
kfree(s->htable);
|
||||
s->htable = NULL;
|
||||
s->nel = 0;
|
||||
s->next_sid = 1;
|
||||
}
|
||||
|
||||
void sidtab_set(struct sidtab *dst, struct sidtab *src)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
SIDTAB_LOCK(src, flags);
|
||||
dst->htable = src->htable;
|
||||
dst->nel = src->nel;
|
||||
dst->next_sid = src->next_sid;
|
||||
dst->shutdown = 0;
|
||||
SIDTAB_UNLOCK(src, flags);
|
||||
}
|
||||
|
||||
void sidtab_shutdown(struct sidtab *s)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
SIDTAB_LOCK(s, flags);
|
||||
s->shutdown = 1;
|
||||
SIDTAB_UNLOCK(s, flags);
|
||||
}
|
59
security/selinux/ss/sidtab.h
Normal file
59
security/selinux/ss/sidtab.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* A security identifier table (sidtab) is a hash table
|
||||
* of security context structures indexed by SID value.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_SIDTAB_H_
|
||||
#define _SS_SIDTAB_H_
|
||||
|
||||
#include "context.h"
|
||||
|
||||
struct sidtab_node {
|
||||
u32 sid; /* security identifier */
|
||||
struct context context; /* security context structure */
|
||||
struct sidtab_node *next;
|
||||
};
|
||||
|
||||
#define SIDTAB_HASH_BITS 7
|
||||
#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
|
||||
#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
|
||||
|
||||
#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
|
||||
|
||||
struct sidtab {
|
||||
struct sidtab_node **htable;
|
||||
unsigned int nel; /* number of elements */
|
||||
unsigned int next_sid; /* next SID to allocate */
|
||||
unsigned char shutdown;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
int sidtab_init(struct sidtab *s);
|
||||
int sidtab_insert(struct sidtab *s, u32 sid, struct context *context);
|
||||
struct context *sidtab_search(struct sidtab *s, u32 sid);
|
||||
|
||||
int sidtab_map(struct sidtab *s,
|
||||
int (*apply) (u32 sid,
|
||||
struct context *context,
|
||||
void *args),
|
||||
void *args);
|
||||
|
||||
void sidtab_map_remove_on_error(struct sidtab *s,
|
||||
int (*apply) (u32 sid,
|
||||
struct context *context,
|
||||
void *args),
|
||||
void *args);
|
||||
|
||||
int sidtab_context_to_sid(struct sidtab *s,
|
||||
struct context *context,
|
||||
u32 *sid);
|
||||
|
||||
void sidtab_hash_eval(struct sidtab *h, char *tag);
|
||||
void sidtab_destroy(struct sidtab *s);
|
||||
void sidtab_set(struct sidtab *dst, struct sidtab *src);
|
||||
void sidtab_shutdown(struct sidtab *s);
|
||||
|
||||
#endif /* _SS_SIDTAB_H_ */
|
||||
|
||||
|
44
security/selinux/ss/symtab.c
Normal file
44
security/selinux/ss/symtab.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Implementation of the symbol table type.
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include "symtab.h"
|
||||
|
||||
static unsigned int symhash(struct hashtab *h, void *key)
|
||||
{
|
||||
char *p, *keyp;
|
||||
unsigned int size;
|
||||
unsigned int val;
|
||||
|
||||
val = 0;
|
||||
keyp = key;
|
||||
size = strlen(keyp);
|
||||
for (p = keyp; (p - keyp) < size; p++)
|
||||
val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
|
||||
return val & (h->size - 1);
|
||||
}
|
||||
|
||||
static int symcmp(struct hashtab *h, void *key1, void *key2)
|
||||
{
|
||||
char *keyp1, *keyp2;
|
||||
|
||||
keyp1 = key1;
|
||||
keyp2 = key2;
|
||||
return strcmp(keyp1, keyp2);
|
||||
}
|
||||
|
||||
|
||||
int symtab_init(struct symtab *s, unsigned int size)
|
||||
{
|
||||
s->table = hashtab_create(symhash, symcmp, size);
|
||||
if (!s->table)
|
||||
return -1;
|
||||
s->nprim = 0;
|
||||
return 0;
|
||||
}
|
||||
|
23
security/selinux/ss/symtab.h
Normal file
23
security/selinux/ss/symtab.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* A symbol table (symtab) maintains associations between symbol
|
||||
* strings and datum values. The type of the datum values
|
||||
* is arbitrary. The symbol table type is implemented
|
||||
* using the hash table type (hashtab).
|
||||
*
|
||||
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
|
||||
*/
|
||||
#ifndef _SS_SYMTAB_H_
|
||||
#define _SS_SYMTAB_H_
|
||||
|
||||
#include "hashtab.h"
|
||||
|
||||
struct symtab {
|
||||
struct hashtab *table; /* hash table (keyed on a string) */
|
||||
u32 nprim; /* number of primary names in table */
|
||||
};
|
||||
|
||||
int symtab_init(struct symtab *s, unsigned int size);
|
||||
|
||||
#endif /* _SS_SYMTAB_H_ */
|
||||
|
||||
|
Reference in New Issue
Block a user