Xen Security Modules: FLASK

Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
This commit is contained in:
kfraser@localhost.localdomain committed 2007-08-31 11:31:18 +01:00
1 parent d046f361dc
commit b1ed041464
44 files changed
+10814

No files matched your search

+8
View File
@@ -81,6 +81,14 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES), -I$(i))
# Enable XSM security module. Enabling XSM requires selection of an
# XSM security module.
XSM_ENABLE ?= n
ifeq ($(XSM_ENABLE),y)
FLASK_ENABLE ?= n
ifeq ($(FLASK_ENABLE),y)
FLASK_DEVELOP ?= y
FLASK_BOOTPARAM ?= y
FLASK_AVC_STATS ?= y
endif
endif
# If ACM_SECURITY = y, then the access control module is compiled
# into Xen and the policy type can be set by the boot policy file
+4
View File
@@ -58,6 +58,10 @@ ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
CFLAGS-y += -g -D__XEN__
CFLAGS-$(XSM_ENABLE) += -DXSM_ENABLE
CFLAGS-$(FLASK_ENABLE) += -DFLASK_ENABLE -DXSM_MAGIC=0xf97cff8c
CFLAGS-$(FLASK_DEVELOP) += -DFLASK_DEVELOP
CFLAGS-$(FLASK_BOOTPARAM) += -DFLASK_BOOTPARAM
CFLAGS-$(FLASK_AVC_STATS) += -DFLASK_AVC_STATS
CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
CFLAGS-$(verbose) += -DVERBOSE
CFLAGS-$(crash_debug) += -DCRASH_DEBUG
+236
View File
@@ -512,6 +512,223 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
EXPORT_SYMBOL(vscnprintf);
/**
* vsscanf - Unformat a buffer into a list of arguments
* @buf: input buffer
* @fmt: format of buffer
* @args: arguments
*/
int vsscanf(const char * buf, const char * fmt, va_list args)
{
const char *str = buf;
const char *next;
char digit;
int num = 0;
int qualifier;
int base;
int field_width;
int is_sign = 0;
while (*fmt && *str) {
/* skip any white space in format */
/* white space in format matchs any amount of
* white space, including none, in the input.
*/
if (isspace(*fmt)) {
while (isspace(*fmt))
++fmt;
while (isspace(*str))
++str;
}
/* anything that is not a conversion must match exactly */
if (*fmt != '%' && *fmt) {
if (*fmt++ != *str++)
break;
continue;
}
if (!*fmt)
break;
++fmt;
/* skip this conversion.
* advance both strings to next white space
*/
if (*fmt == '*') {
while (!isspace(*fmt) && *fmt)
fmt++;
while (!isspace(*str) && *str)
str++;
continue;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
/* get conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z'
|| *fmt == 'z') {
qualifier = *fmt++;
if (unlikely(qualifier == *fmt)) {
if (qualifier == 'h') {
qualifier = 'H';
fmt++;
} else if (qualifier == 'l') {
qualifier = 'L';
fmt++;
}
}
}
base = 10;
is_sign = 0;
if (!*fmt || !*str)
break;
switch(*fmt++) {
case 'c': {
char *s = (char *) va_arg(args,char*);
if (field_width == -1)
field_width = 1;
do {
*s++ = *str++;
} while (--field_width > 0 && *str);
num++;
}
continue;
case 's': {
char *s = (char *) va_arg(args, char *);
if(field_width == -1)
field_width = INT_MAX;
/* first, skip leading white space in buffer */
while (isspace(*str))
str++;
/* now copy until next white space */
while (*str && !isspace(*str) && field_width--)
*s++ = *str++;
*s = '\0';
num++;
}
continue;
case 'n': {
/* return number of characters read so far */
int *i = (int *)va_arg(args,int*);
*i = str - buf;
}
continue;
case 'o':
base = 8;
break;
case 'x':
case 'X':
base = 16;
break;
case 'i':
base = 0;
case 'd':
is_sign = 1;
case 'u':
break;
case '%':
/* looking for '%' in str */
if (*str++ != '%')
return num;
continue;
default:
/* invalid format; stop here */
return num;
}
/* have some sort of integer conversion.
* first, skip white space in buffer.
*/
while (isspace(*str))
str++;
digit = *str;
if (is_sign && digit == '-')
digit = *(str + 1);
if (!digit || (base == 16 && !isxdigit(digit))
|| (base == 10 && !isdigit(digit))
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|| (base == 0 && !isdigit(digit)))
break;
switch(qualifier) {
case 'H': /* that's 'hh' in format */
if (is_sign) {
signed char *s = (signed char *) va_arg(args,signed char *);
*s = (signed char) simple_strtol(str,&next,base);
} else {
unsigned char *s = (unsigned char *)
va_arg(args, unsigned char *);
*s = (unsigned char) simple_strtoul(str, &next, base);
}
break;
case 'h':
if (is_sign) {
short *s = (short *) va_arg(args,short *);
*s = (short) simple_strtol(str,&next,base);
} else {
unsigned short *s = (unsigned short *)
va_arg(args, unsigned short *);
*s = (unsigned short) simple_strtoul(str, &next, base);
}
break;
case 'l':
if (is_sign) {
long *l = (long *) va_arg(args,long *);
*l = simple_strtol(str,&next,base);
} else {
unsigned long *l = (unsigned long*)
va_arg(args,unsigned long*);
*l = simple_strtoul(str,&next,base);
}
break;
case 'L':
if (is_sign) {
long long *l = (long long*) va_arg(args,long long *);
*l = simple_strtoll(str,&next,base);
} else {
unsigned long long *l = (unsigned long long*)
va_arg(args,unsigned long long*);
*l = simple_strtoull(str,&next,base);
}
break;
case 'Z':
case 'z': {
size_t *s = (size_t*) va_arg(args,size_t*);
*s = (size_t) simple_strtoul(str,&next,base);
}
break;
default:
if (is_sign) {
int *i = (int *) va_arg(args, int*);
*i = (int) simple_strtol(str,&next,base);
} else {
unsigned int *i = (unsigned int*)
va_arg(args, unsigned int*);
*i = (unsigned int) simple_strtoul(str,&next,base);
}
break;
}
num++;
if (!next)
break;
str = next;
}
return num;
}
EXPORT_SYMBOL(vsscanf);
/**
* snprintf - Format a string and place it in a buffer
* @buf: The buffer to place the result into
@@ -561,6 +778,25 @@ int scnprintf(char * buf, size_t size, const char *fmt, ...)
}
EXPORT_SYMBOL(scnprintf);
/**
* sscanf - Unformat a buffer into a list of arguments
* @buf: input buffer
* @fmt: formatting of buffer
* @...: resulting arguments
*/
int sscanf(const char * buf, const char * fmt, ...)
{
va_list args;
int i;
va_start(args,fmt);
i = vsscanf(buf,fmt,args);
va_end(args);
return i;
}
EXPORT_SYMBOL(sscanf);
/*
* Local variables:
* mode: C
+45
View File
@@ -0,0 +1,45 @@
/*
* This file contains the flask_op hypercall commands and definitions.
*
* Author: George Coker, <gscoker@alpha.ncsc.mil>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#ifndef __FLASK_OP_H__
#define __FLASK_OP_H__
#define FLASK_LOAD 1
#define FLASK_GETENFORCE 2
#define FLASK_SETENFORCE 3
#define FLASK_CONTEXT_TO_SID 4
#define FLASK_SID_TO_CONTEXT 5
#define FLASK_ACCESS 6
#define FLASK_CREATE 7
#define FLASK_RELABEL 8
#define FLASK_USER 9
#define FLASK_POLICYVERS 10
#define FLASK_GETBOOL 11
#define FLASK_SETBOOL 12
#define FLASK_COMMITBOOLS 13
#define FLASK_MLS 14
#define FLASK_DISABLE 15
#define FLASK_GETAVC_THRESHOLD 16
#define FLASK_SETAVC_THRESHOLD 17
#define FLASK_AVC_HASHSTATS 18
#define FLASK_AVC_CACHESTATS 19
#define FLASK_MEMBER 20
typedef struct flask_op {
int cmd;
int size;
char *buf;
} flask_op_t;
DEFINE_XEN_GUEST_HANDLE(flask_op_t);
long do_flask_op (XEN_GUEST_HANDLE(xsm_op_t) u_flask_op);
#endif
+4
View File
@@ -75,6 +75,10 @@ extern int scnprintf(char * buf, size_t size, const char * fmt, ...)
__attribute__ ((format (printf, 3, 4)));
extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
__attribute__ ((format (printf, 3, 0)));
extern int sscanf(const char * buf, const char * fmt, ...)
__attribute__ ((format (scanf, 2, 3)));
extern int vsscanf(const char * buf, const char * fmt, va_list args)
__attribute__ ((format (scanf, 2, 0)));
long simple_strtol(
const char *cp,const char **endp, unsigned int base);
+2
View File
@@ -3,3 +3,5 @@ obj-y += xsm_policy.o
ifeq ($(XSM_ENABLE),y)
obj-y += dummy.o
endif
subdir-$(FLASK_ENABLE) += flask
+7
View File
@@ -0,0 +1,7 @@
obj-y += avc.o
obj-y += hooks.o
obj-y += flask_op.o
subdir-y += ss
CFLAGS += -I./include
+817
View File
@@ -0,0 +1,817 @@
/*
* Implementation of the kernel access vector cache (AVC).
*
* Authors: Stephen Smalley, <sds@epoch.ncsc.mil>
* James Morris <jmorris@redhat.com>
*
* Update: KaiGai, Kohei <kaigai@ak.jp.nec.com>
* Replaced the avc_lock spinlock by RCU.
*
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/types.h>
#include <xen/list.h>
#include <xen/spinlock.h>
#include <xen/prefetch.h>
#include <xen/kernel.h>
#include <xen/sched.h>
#include <xen/init.h>
#include <xen/rcupdate.h>
#include <asm/atomic.h>
#include <asm/current.h>
#include "avc.h"
#include "avc_ss.h"
static const struct av_perm_to_string
{
u16 tclass;
u32 value;
const char *name;
} av_perm_to_string[] = {
#define S_(c, v, s) { c, v, s },
#include "av_perm_to_string.h"
#undef S_
};
static const char *class_to_string[] = {
#define S_(s) s,
#include "class_to_string.h"
#undef S_
};
#define TB_(s) static const char * s [] = {
#define TE_(s) };
#define S_(s) s,
#include "common_perm_to_string.h"
#undef TB_
#undef TE_
#undef S_
static const struct av_inherit
{
u16 tclass;
const char **common_pts;
u32 common_base;
} av_inherit[] = {
#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
#include "av_inherit.h"
#undef S_
};
#define AVC_CACHE_SLOTS 512
#define AVC_DEF_CACHE_THRESHOLD 512
#define AVC_CACHE_RECLAIM 16
#ifdef FLASK_AVC_STATS
#define avc_cache_stats_incr(field) \
do { \
__get_cpu_var(avc_cache_stats).field++; \
} while (0)
#else
#define avc_cache_stats_incr(field) do {} while (0)
#endif
struct avc_entry {
u32 ssid;
u32 tsid;
u16 tclass;
struct av_decision avd;
atomic_t used; /* used recently */
};
struct avc_node {
struct avc_entry ae;
struct list_head list;
struct rcu_head rhead;
};
struct avc_cache {
struct list_head slots[AVC_CACHE_SLOTS];
spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
atomic_t lru_hint; /* LRU hint for reclaim scan */
atomic_t active_nodes;
u32 latest_notif; /* latest revocation notification */
};
struct avc_callback_node {
int (*callback) (u32 event, u32 ssid, u32 tsid,
u16 tclass, u32 perms,
u32 *out_retained);
u32 events;
u32 ssid;
u32 tsid;
u16 tclass;
u32 perms;
struct avc_callback_node *next;
};
/* Exported via Flask hypercall */
unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
#ifdef FLASK_AVC_STATS
DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
#endif
static struct avc_cache avc_cache;
static struct avc_callback_node *avc_callbacks;
static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
{
return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
}
/**
* avc_dump_av - Display an access vector in human-readable form.
* @tclass: target security class
* @av: access vector
*/
static void avc_dump_av(u16 tclass, u32 av)
{
const char **common_pts = NULL;
u32 common_base = 0;
int i, i2, perm;
if ( av == 0 )
{
printk(" null");
return;
}
for ( i = 0; i < ARRAY_SIZE(av_inherit); i++ )
{
if (av_inherit[i].tclass == tclass)
{
common_pts = av_inherit[i].common_pts;
common_base = av_inherit[i].common_base;
break;
}
}
printk(" {");
i = 0;
perm = 1;
while ( perm < common_base )
{
if (perm & av)
{
printk(" %s", common_pts[i]);
av &= ~perm;
}
i++;
perm <<= 1;
}
while ( i < sizeof(av) * 8 )
{
if ( perm & av )
{
for ( i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++ )
{
if ( (av_perm_to_string[i2].tclass == tclass) &&
(av_perm_to_string[i2].value == perm) )
break;
}
if ( i2 < ARRAY_SIZE(av_perm_to_string) )
{
printk(" %s", av_perm_to_string[i2].name);
av &= ~perm;
}
}
i++;
perm <<= 1;
}
if ( av )
printk(" 0x%x", av);
printk(" }");
}
/**
* avc_dump_query - Display a SID pair and a class in human-readable form.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
*/
static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
{
int rc;
char *scontext;
u32 scontext_len;
rc = security_sid_to_context(ssid, &scontext, &scontext_len);
if ( rc )
printk("ssid=%d", ssid);
else
{
printk("scontext=%s", scontext);
xfree(scontext);
}
rc = security_sid_to_context(tsid, &scontext, &scontext_len);
if ( rc )
printk(" tsid=%d", tsid);
else
{
printk(" tcontext=%s", scontext);
xfree(scontext);
}
printk("\n");
printk("tclass=%s", class_to_string[tclass]);
}
/**
* avc_init - Initialize the AVC.
*
* Initialize the access vector cache.
*/
void __init avc_init(void)
{
int i;
for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
{
INIT_LIST_HEAD(&avc_cache.slots[i]);
spin_lock_init(&avc_cache.slots_lock[i]);
}
atomic_set(&avc_cache.active_nodes, 0);
atomic_set(&avc_cache.lru_hint, 0);
printk("AVC INITIALIZED\n");
}
int avc_get_hash_stats(char *page)
{
int i, chain_len, max_chain_len, slots_used;
struct avc_node *node;
rcu_read_lock();
slots_used = 0;
max_chain_len = 0;
for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
{
if ( !list_empty(&avc_cache.slots[i]) )
{
slots_used++;
chain_len = 0;
list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
chain_len++;
if ( chain_len > max_chain_len )
max_chain_len = chain_len;
}
}
rcu_read_unlock();
return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
"longest chain: %d\n",
atomic_read(&avc_cache.active_nodes),
slots_used, AVC_CACHE_SLOTS, max_chain_len);
}
static void avc_node_free(struct rcu_head *rhead)
{
struct avc_node *node = container_of(rhead, struct avc_node, rhead);
xfree(node);
avc_cache_stats_incr(frees);
}
static void avc_node_delete(struct avc_node *node)
{
list_del_rcu(&node->list);
call_rcu(&node->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes);
}
static void avc_node_kill(struct avc_node *node)
{
xfree(node);
avc_cache_stats_incr(frees);
atomic_dec(&avc_cache.active_nodes);
}
static void avc_node_replace(struct avc_node *new, struct avc_node *old)
{
list_replace_rcu(&old->list, &new->list);
call_rcu(&old->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes);
}
static inline int avc_reclaim_node(void)
{
struct avc_node *node;
int hvalue, try, ecx;
unsigned long flags;
for ( try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ )
{
atomic_inc(&avc_cache.lru_hint);
hvalue = atomic_read(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
list_for_each_entry(node, &avc_cache.slots[hvalue], list)
{
if ( atomic_dec_and_test(&node->ae.used) )
{
/* Recently Unused */
avc_node_delete(node);
avc_cache_stats_incr(reclaims);
ecx++;
if ( ecx >= AVC_CACHE_RECLAIM )
{
spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
goto out;
}
}
}
spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
}
out:
return ecx;
}
static struct avc_node *avc_alloc_node(void)
{
struct avc_node *node;
node = xmalloc(struct avc_node);
if (!node)
goto out;
memset(node, 0, sizeof(*node));
INIT_RCU_HEAD(&node->rhead);
INIT_LIST_HEAD(&node->list);
atomic_set(&node->ae.used, 1);
avc_cache_stats_incr(allocations);
atomic_inc(&avc_cache.active_nodes);
if ( atomic_read(&avc_cache.active_nodes) > avc_cache_threshold )
avc_reclaim_node();
out:
return node;
}
static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
{
node->ae.ssid = ssid;
node->ae.tsid = tsid;
node->ae.tclass = tclass;
memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
}
static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
{
struct avc_node *node, *ret = NULL;
int hvalue;
hvalue = avc_hash(ssid, tsid, tclass);
list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list)
{
if ( ssid == node->ae.ssid && tclass == node->ae.tclass &&
tsid == node->ae.tsid )
{
ret = node;
break;
}
}
if ( ret == NULL )
{
/* cache miss */
goto out;
}
/* cache hit */
if ( atomic_read(&ret->ae.used) != 1 )
atomic_set(&ret->ae.used, 1);
out:
return ret;
}
/**
* avc_lookup - Look up an AVC entry.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
*
* Look up an AVC entry that is valid for the
* @requested permissions between the SID pair
* (@ssid, @tsid), interpreting the permissions
* based on @tclass. If a valid AVC entry exists,
* then this function return the avc_node.
* Otherwise, this function returns NULL.
*/
static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
{
struct avc_node *node;
avc_cache_stats_incr(lookups);
node = avc_search_node(ssid, tsid, tclass);
if ( node && ((node->ae.avd.decided & requested) == requested) )
{
avc_cache_stats_incr(hits);
goto out;
}
node = NULL;
avc_cache_stats_incr(misses);
out:
return node;
}
static int avc_latest_notif_update(int seqno, int is_insert)
{
int ret = 0;
static DEFINE_SPINLOCK(notif_lock);
unsigned long flag;
spin_lock_irqsave(&notif_lock, flag);
if ( is_insert )
{
if ( seqno < avc_cache.latest_notif )
{
printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
seqno, avc_cache.latest_notif);
ret = -EAGAIN;
}
}
else
{
if ( seqno > avc_cache.latest_notif )
avc_cache.latest_notif = seqno;
}
spin_unlock_irqrestore(&notif_lock, flag);
return ret;
}
/**
* avc_insert - Insert an AVC entry.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @ae: AVC entry
*
* Insert an AVC entry for the SID pair
* (@ssid, @tsid) and class @tclass.
* The access vectors and the sequence number are
* normally provided by the security server in
* response to a security_compute_av() call. If the
* sequence number @ae->avd.seqno is not less than the latest
* revocation notification, then the function copies
* the access vectors into a cache entry, returns
* avc_node inserted. Otherwise, this function returns NULL.
*/
static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
{
struct avc_node *pos, *node = NULL;
int hvalue;
unsigned long flag;
if ( avc_latest_notif_update(ae->avd.seqno, 1) )
goto out;
node = avc_alloc_node();
if ( node )
{
hvalue = avc_hash(ssid, tsid, tclass);
avc_node_populate(node, ssid, tsid, tclass, ae);
spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
{
if ( pos->ae.ssid == ssid && pos->ae.tsid == tsid &&
pos->ae.tclass == tclass )
{
avc_node_replace(node, pos);
goto found;
}
}
list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
found:
spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
}
out:
return node;
}
/**
* avc_audit - Audit the granting or denial of permissions.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions
* @avd: access vector decisions
* @result: result from avc_has_perm_noaudit
* @a: auxiliary audit data
*
* Audit the granting or denial of permissions in accordance
* with the policy. This function is typically called by
* avc_has_perm() after a permission check, but can also be
* called directly by callers who use avc_has_perm_noaudit()
* in order to separate the permission check from the auditing.
* For example, this separation is useful when the permission check must
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *a)
{
struct domain *d = current->domain;
u32 denied, audited;
denied = requested & ~avd->allowed;
if ( denied )
{
audited = denied;
if ( !(audited & avd->auditdeny) )
return;
}
else if ( result )
{
audited = denied = requested;
}
else
{
audited = requested;
if ( !(audited & avd->auditallow) )
return;
}
printk("avc: %s ", denied ? "denied" : "granted");
avc_dump_av(tclass, audited);
printk(" for ");
if ( a && a->d )
d = a->d;
if ( d )
printk("domid=%d", d->domain_id);
printk("\n");
avc_dump_query(ssid, tsid, tclass);
printk("\n");
}
/**
* avc_add_callback - Register a callback for security events.
* @callback: callback function
* @events: security events
* @ssid: source security identifier or %SECSID_WILD
* @tsid: target security identifier or %SECSID_WILD
* @tclass: target security class
* @perms: permissions
*
* Register a callback function for events in the set @events
* related to the SID pair (@ssid, @tsid) and
* and the permissions @perms, interpreting
* @perms based on @tclass. Returns %0 on success or
* -%ENOMEM if insufficient memory exists to add the callback.
*/
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u16 tclass,
u32 perms, u32 *out_retained), u32 events, u32 ssid, u32 tsid,
u16 tclass, u32 perms)
{
struct avc_callback_node *c;
int rc = 0;
c = xmalloc(struct avc_callback_node);
if ( !c )
{
rc = -ENOMEM;
goto out;
}
c->callback = callback;
c->events = events;
c->ssid = ssid;
c->tsid = tsid;
c->perms = perms;
c->next = avc_callbacks;
avc_callbacks = c;
out:
return rc;
}
static inline int avc_sidcmp(u32 x, u32 y)
{
return (x == y || x == SECSID_WILD || y == SECSID_WILD);
}
/**
* avc_update_node Update an AVC entry
* @event : Updating event
* @perms : Permission mask bits
* @ssid,@tsid,@tclass : identifier of an AVC entry
*
* if a valid AVC entry doesn't exist,this function returns -ENOENT.
* if kmalloc() called internal returns NULL, this function returns -ENOMEM.
* otherwise, this function update the AVC entry. The original AVC-entry object
* will release later by RCU.
*/
static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
{
int hvalue, rc = 0;
unsigned long flag;
struct avc_node *pos, *node, *orig = NULL;
node = avc_alloc_node();
if ( !node )
{
rc = -ENOMEM;
goto out;
}
hvalue = avc_hash(ssid, tsid, tclass);
spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
{
if ( ssid==pos->ae.ssid && tsid==pos->ae.tsid &&
tclass==pos->ae.tclass )
{
orig = pos;
break;
}
}
if ( !orig )
{
rc = -ENOENT;
avc_node_kill(node);
goto out_unlock;
}
/*
* Copy and replace original node.
*/
avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
switch ( event )
{
case AVC_CALLBACK_GRANT:
node->ae.avd.allowed |= perms;
break;
case AVC_CALLBACK_TRY_REVOKE:
case AVC_CALLBACK_REVOKE:
node->ae.avd.allowed &= ~perms;
break;
case AVC_CALLBACK_AUDITALLOW_ENABLE:
node->ae.avd.auditallow |= perms;
break;
case AVC_CALLBACK_AUDITALLOW_DISABLE:
node->ae.avd.auditallow &= ~perms;
break;
case AVC_CALLBACK_AUDITDENY_ENABLE:
node->ae.avd.auditdeny |= perms;
break;
case AVC_CALLBACK_AUDITDENY_DISABLE:
node->ae.avd.auditdeny &= ~perms;
break;
}
avc_node_replace(node, orig);
out_unlock:
spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
out:
return rc;
}
/**
* avc_ss_reset - Flush the cache and revalidate migrated permissions.
* @seqno: policy sequence number
*/
int avc_ss_reset(u32 seqno)
{
struct avc_callback_node *c;
int i, rc = 0;
unsigned long flag;
struct avc_node *node;
for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
{
spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
list_for_each_entry(node, &avc_cache.slots[i], list)
avc_node_delete(node);
spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
}
for ( c = avc_callbacks; c; c = c->next )
{
if ( c->events & AVC_CALLBACK_RESET )
{
rc = c->callback(AVC_CALLBACK_RESET,
0, 0, 0, 0, NULL);
if ( rc )
goto out;
}
}
avc_latest_notif_update(seqno, 0);
out:
return rc;
}
/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
* @avd: access vector decisions
*
* Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions
* based on @tclass, and call the security server on a cache miss to obtain
* a new decision and add it to the cache. Return a copy of the decisions
* in @avd. Return %0 if all @requested permissions are granted,
* -%EACCES if any permissions are denied, or another -errno upon
* other errors. This function is typically called by avc_has_perm(),
* but may also be called directly to separate permission checking from
* auditing, e.g. in cases where a lock must be held for the check but
* should be released for the auditing.
*/
int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd)
{
struct avc_node *node;
struct avc_entry entry, *p_ae;
int rc = 0;
u32 denied;
rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass, requested);
if ( !node )
{
rcu_read_unlock();
rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
if ( rc )
goto out;
rcu_read_lock();
node = avc_insert(ssid,tsid,tclass,&entry);
}
p_ae = node ? &node->ae : &entry;
if ( avd )
memcpy(avd, &p_ae->avd, sizeof(*avd));
denied = requested & ~(p_ae->avd.allowed);
if ( !requested || denied )
{
if ( flask_enforcing )
rc = -EACCES;
else
if ( node )
avc_update_node(AVC_CALLBACK_GRANT,requested,
ssid,tsid,tclass);
}
rcu_read_unlock();
out:
return rc;
}
/**
* avc_has_perm - Check permissions and perform any appropriate auditing.
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
* @auditdata: auxiliary audit data
*
* Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions
* based on @tclass, and call the security server on a cache miss to obtain
* a new decision and add it to the cache. Audit the granting or denial of
* permissions in accordance with the policy. Return %0 if all @requested
* permissions are granted, -%EACCES if any permissions are denied, or
* another -errno upon other errors.
*/
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct avc_audit_data *auditdata)
{
struct av_decision avd;
int rc;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
return rc;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
/* This file is automatically generated. Do not edit. */
+99
View File
@@ -0,0 +1,99 @@
/* This file is automatically generated. Do not edit. */
S_(SECCLASS_XEN, XEN__SCHEDULER, "scheduler")
S_(SECCLASS_XEN, XEN__SETTIME, "settime")
S_(SECCLASS_XEN, XEN__TBUFCONTROL, "tbufcontrol")
S_(SECCLASS_XEN, XEN__READCONSOLE, "readconsole")
S_(SECCLASS_XEN, XEN__CLEARCONSOLE, "clearconsole")
S_(SECCLASS_XEN, XEN__PERFCONTROL, "perfcontrol")
S_(SECCLASS_XEN, XEN__MTRR_ADD, "mtrr_add")
S_(SECCLASS_XEN, XEN__MTRR_DEL, "mtrr_del")
S_(SECCLASS_XEN, XEN__MTRR_READ, "mtrr_read")
S_(SECCLASS_XEN, XEN__MICROCODE, "microcode")
S_(SECCLASS_XEN, XEN__PHYSINFO, "physinfo")
S_(SECCLASS_XEN, XEN__QUIRK, "quirk")
S_(SECCLASS_XEN, XEN__WRITECONSOLE, "writeconsole")
S_(SECCLASS_XEN, XEN__READAPIC, "readapic")
S_(SECCLASS_XEN, XEN__WRITEAPIC, "writeapic")
S_(SECCLASS_XEN, XEN__PRIVPROFILE, "privprofile")
S_(SECCLASS_XEN, XEN__NONPRIVPROFILE, "nonprivprofile")
S_(SECCLASS_XEN, XEN__KEXEC, "kexec")
S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUCONTEXT, "setvcpucontext")
S_(SECCLASS_DOMAIN, DOMAIN__PAUSE, "pause")
S_(SECCLASS_DOMAIN, DOMAIN__UNPAUSE, "unpause")
S_(SECCLASS_DOMAIN, DOMAIN__RESUME, "resume")
S_(SECCLASS_DOMAIN, DOMAIN__CREATE, "create")
S_(SECCLASS_DOMAIN, DOMAIN__MAX_VCPUS, "max_vcpus")
S_(SECCLASS_DOMAIN, DOMAIN__DESTROY, "destroy")
S_(SECCLASS_DOMAIN, DOMAIN__SETVCPUAFFINITY, "setvcpuaffinity")
S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUAFFINITY, "getvcpuaffinity")
S_(SECCLASS_DOMAIN, DOMAIN__SCHEDULER, "scheduler")
S_(SECCLASS_DOMAIN, DOMAIN__GETDOMAININFO, "getdomaininfo")
S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUINFO, "getvcpuinfo")
S_(SECCLASS_DOMAIN, DOMAIN__GETVCPUCONTEXT, "getvcpucontext")
S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINMAXMEM, "setdomainmaxmem")
S_(SECCLASS_DOMAIN, DOMAIN__SETDOMAINHANDLE, "setdomainhandle")
S_(SECCLASS_DOMAIN, DOMAIN__SETDEBUGGING, "setdebugging")
S_(SECCLASS_DOMAIN, DOMAIN__HYPERCALL, "hypercall")
S_(SECCLASS_DOMAIN, DOMAIN__TRANSITION, "transition")
S_(SECCLASS_DOMAIN, DOMAIN__SETTIME, "settime")
S_(SECCLASS_DOMAIN, DOMAIN__SHUTDOWN, "shutdown")
S_(SECCLASS_DOMAIN, DOMAIN__SETADDRSIZE, "setaddrsize")
S_(SECCLASS_DOMAIN, DOMAIN__GETADDRSIZE, "getaddrsize")
S_(SECCLASS_HVM, HVM__SETHVMC, "sethvmc")
S_(SECCLASS_HVM, HVM__GETHVMC, "gethvmc")
S_(SECCLASS_HVM, HVM__SETPARAM, "setparam")
S_(SECCLASS_HVM, HVM__GETPARAM, "getparam")
S_(SECCLASS_HVM, HVM__PCILEVEL, "pcilevel")
S_(SECCLASS_HVM, HVM__IRQLEVEL, "irqlevel")
S_(SECCLASS_HVM, HVM__PCIROUTE, "pciroute")
S_(SECCLASS_EVENT, EVENT__BIND, "bind")
S_(SECCLASS_EVENT, EVENT__CLOSE, "close")
S_(SECCLASS_EVENT, EVENT__SEND, "send")
S_(SECCLASS_EVENT, EVENT__STATUS, "status")
S_(SECCLASS_EVENT, EVENT__UNMASK, "unmask")
S_(SECCLASS_EVENT, EVENT__NOTIFY, "notify")
S_(SECCLASS_EVENT, EVENT__CREATE, "create")
S_(SECCLASS_EVENT, EVENT__ALLOC, "alloc")
S_(SECCLASS_EVENT, EVENT__VECTOR, "vector")
S_(SECCLASS_EVENT, EVENT__RESET, "reset")
S_(SECCLASS_GRANT, GRANT__MAP_READ, "map_read")
S_(SECCLASS_GRANT, GRANT__MAP_WRITE, "map_write")
S_(SECCLASS_GRANT, GRANT__UNMAP, "unmap")
S_(SECCLASS_GRANT, GRANT__TRANSFER, "transfer")
S_(SECCLASS_GRANT, GRANT__SETUP, "setup")
S_(SECCLASS_GRANT, GRANT__COPY, "copy")
S_(SECCLASS_GRANT, GRANT__QUERY, "query")
S_(SECCLASS_MMU, MMU__MAP_READ, "map_read")
S_(SECCLASS_MMU, MMU__MAP_WRITE, "map_write")
S_(SECCLASS_MMU, MMU__PAGEINFO, "pageinfo")
S_(SECCLASS_MMU, MMU__PAGELIST, "pagelist")
S_(SECCLASS_MMU, MMU__ADJUST, "adjust")
S_(SECCLASS_MMU, MMU__STAT, "stat")
S_(SECCLASS_MMU, MMU__TRANSLATEGP, "translategp")
S_(SECCLASS_MMU, MMU__UPDATEMP, "updatemp")
S_(SECCLASS_MMU, MMU__PHYSMAP, "physmap")
S_(SECCLASS_MMU, MMU__PINPAGE, "pinpage")
S_(SECCLASS_MMU, MMU__MFNLIST, "mfnlist")
S_(SECCLASS_MMU, MMU__MEMORYMAP, "memorymap")
S_(SECCLASS_SHADOW, SHADOW__DISABLE, "disable")
S_(SECCLASS_SHADOW, SHADOW__ENABLE, "enable")
S_(SECCLASS_SHADOW, SHADOW__LOGDIRTY, "logdirty")
S_(SECCLASS_RESOURCE, RESOURCE__ADD, "add")
S_(SECCLASS_RESOURCE, RESOURCE__REMOVE, "remove")
S_(SECCLASS_RESOURCE, RESOURCE__USE, "use")
S_(SECCLASS_RESOURCE, RESOURCE__ADD_IRQ, "add_irq")
S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IRQ, "remove_irq")
S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOPORT, "add_ioport")
S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOPORT, "remove_ioport")
S_(SECCLASS_RESOURCE, RESOURCE__ADD_IOMEM, "add_iomem")
S_(SECCLASS_RESOURCE, RESOURCE__REMOVE_IOMEM, "remove_iomem")
S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
S_(SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, "compute_member")
S_(SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, "check_context")
S_(SECCLASS_SECURITY, SECURITY__LOAD_POLICY, "load_policy")
S_(SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, "compute_relabel")
S_(SECCLASS_SECURITY, SECURITY__COMPUTE_USER, "compute_user")
S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
+108
View File
@@ -0,0 +1,108 @@
/* This file is automatically generated. Do not edit. */
#define XEN__SCHEDULER 0x00000001UL
#define XEN__SETTIME 0x00000002UL
#define XEN__TBUFCONTROL 0x00000004UL
#define XEN__READCONSOLE 0x00000008UL
#define XEN__CLEARCONSOLE 0x00000010UL
#define XEN__PERFCONTROL 0x00000020UL
#define XEN__MTRR_ADD 0x00000040UL
#define XEN__MTRR_DEL 0x00000080UL
#define XEN__MTRR_READ 0x00000100UL
#define XEN__MICROCODE 0x00000200UL
#define XEN__PHYSINFO 0x00000400UL
#define XEN__QUIRK 0x00000800UL
#define XEN__WRITECONSOLE 0x00001000UL
#define XEN__READAPIC 0x00002000UL
#define XEN__WRITEAPIC 0x00004000UL
#define XEN__PRIVPROFILE 0x00008000UL
#define XEN__NONPRIVPROFILE 0x00010000UL
#define XEN__KEXEC 0x00020000UL
#define DOMAIN__SETVCPUCONTEXT 0x00000001UL
#define DOMAIN__PAUSE 0x00000002UL
#define DOMAIN__UNPAUSE 0x00000004UL
#define DOMAIN__RESUME 0x00000008UL
#define DOMAIN__CREATE 0x00000010UL
#define DOMAIN__MAX_VCPUS 0x00000020UL
#define DOMAIN__DESTROY 0x00000040UL
#define DOMAIN__SETVCPUAFFINITY 0x00000080UL
#define DOMAIN__GETVCPUAFFINITY 0x00000100UL
#define DOMAIN__SCHEDULER 0x00000200UL
#define DOMAIN__GETDOMAININFO 0x00000400UL
#define DOMAIN__GETVCPUINFO 0x00000800UL
#define DOMAIN__GETVCPUCONTEXT 0x00001000UL
#define DOMAIN__SETDOMAINMAXMEM 0x00002000UL
#define DOMAIN__SETDOMAINHANDLE 0x00004000UL
#define DOMAIN__SETDEBUGGING 0x00008000UL
#define DOMAIN__HYPERCALL 0x00010000UL
#define DOMAIN__TRANSITION 0x00020000UL
#define DOMAIN__SETTIME 0x00040000UL
#define DOMAIN__SHUTDOWN 0x00080000UL
#define DOMAIN__SETADDRSIZE 0x00100000UL
#define DOMAIN__GETADDRSIZE 0x00200000UL
#define HVM__SETHVMC 0x00000001UL
#define HVM__GETHVMC 0x00000002UL
#define HVM__SETPARAM 0x00000004UL
#define HVM__GETPARAM 0x00000008UL
#define HVM__PCILEVEL 0x00000010UL
#define HVM__IRQLEVEL 0x00000020UL
#define HVM__PCIROUTE 0x00000040UL
#define EVENT__BIND 0x00000001UL
#define EVENT__CLOSE 0x00000002UL
#define EVENT__SEND 0x00000004UL
#define EVENT__STATUS 0x00000008UL
#define EVENT__UNMASK 0x00000010UL
#define EVENT__NOTIFY 0x00000020UL
#define EVENT__CREATE 0x00000040UL
#define EVENT__ALLOC 0x00000080UL
#define EVENT__VECTOR 0x00000100UL
#define EVENT__RESET 0x00000200UL
#define GRANT__MAP_READ 0x00000001UL
#define GRANT__MAP_WRITE 0x00000002UL
#define GRANT__UNMAP 0x00000004UL
#define GRANT__TRANSFER 0x00000008UL
#define GRANT__SETUP 0x00000010UL
#define GRANT__COPY 0x00000020UL
#define GRANT__QUERY 0x00000040UL
#define MMU__MAP_READ 0x00000001UL
#define MMU__MAP_WRITE 0x00000002UL
#define MMU__PAGEINFO 0x00000004UL
#define MMU__PAGELIST 0x00000008UL
#define MMU__ADJUST 0x00000010UL
#define MMU__STAT 0x00000020UL
#define MMU__TRANSLATEGP 0x00000040UL
#define MMU__UPDATEMP 0x00000080UL
#define MMU__PHYSMAP 0x00000100UL
#define MMU__PINPAGE 0x00000200UL
#define MMU__MFNLIST 0x00000400UL
#define MMU__MEMORYMAP 0x00000800UL
#define SHADOW__DISABLE 0x00000001UL
#define SHADOW__ENABLE 0x00000002UL
#define SHADOW__LOGDIRTY 0x00000004UL
#define RESOURCE__ADD 0x00000001UL
#define RESOURCE__REMOVE 0x00000002UL
#define RESOURCE__USE 0x00000004UL
#define RESOURCE__ADD_IRQ 0x00000008UL
#define RESOURCE__REMOVE_IRQ 0x00000010UL
#define RESOURCE__ADD_IOPORT 0x00000020UL
#define RESOURCE__REMOVE_IOPORT 0x00000040UL
#define RESOURCE__ADD_IOMEM 0x00000080UL
#define RESOURCE__REMOVE_IOMEM 0x00000100UL
#define SECURITY__COMPUTE_AV 0x00000001UL
#define SECURITY__COMPUTE_CREATE 0x00000002UL
#define SECURITY__COMPUTE_MEMBER 0x00000004UL
#define SECURITY__CHECK_CONTEXT 0x00000008UL
#define SECURITY__LOAD_POLICY 0x00000010UL
#define SECURITY__COMPUTE_RELABEL 0x00000020UL
#define SECURITY__COMPUTE_USER 0x00000040UL
#define SECURITY__SETENFORCE 0x00000080UL
#define SECURITY__SETBOOL 0x00000100UL
#define SECURITY__SETSECPARAM 0x00000200UL
+106
View File
@@ -0,0 +1,106 @@
/*
* Access vector cache interface for object managers.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#ifndef _FLASK_AVC_H_
#define _FLASK_AVC_H_
#include <xen/errno.h>
#include <xen/lib.h>
#include <xen/spinlock.h>
#include <asm/percpu.h>
#include "flask.h"
#include "av_permissions.h"
#include "security.h"
#ifdef FLASK_DEVELOP
extern int flask_enforcing;
#else
#define flask_enforcing 1
#endif
/*
* An entry in the AVC.
*/
struct avc_entry;
struct task_struct;
struct vfsmount;
struct dentry;
struct inode;
struct sock;
struct sk_buff;
/* Auxiliary data to use in generating the audit record. */
struct avc_audit_data {
char type;
#define AVC_AUDIT_DATA_FS 1
#define AVC_AUDIT_DATA_NET 2
#define AVC_AUDIT_DATA_CAP 3
#define AVC_AUDIT_DATA_IPC 4
struct domain *d;
};
#define v4info fam.v4
#define v6info fam.v6
/* Initialize an AVC audit data structure. */
#define AVC_AUDIT_DATA_INIT(_d,_t) \
{ memset((_d), 0, sizeof(struct avc_audit_data)); \
(_d)->type = AVC_AUDIT_DATA_##_t; }
/*
* AVC statistics
*/
struct avc_cache_stats
{
unsigned int lookups;
unsigned int hits;
unsigned int misses;
unsigned int allocations;
unsigned int reclaims;
unsigned int frees;
};
/*
* AVC operations
*/
void avc_init(void);
void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct avc_audit_data *auditdata);
#define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2
#define AVC_CALLBACK_REVOKE 4
#define AVC_CALLBACK_RESET 8
#define AVC_CALLBACK_AUDITALLOW_ENABLE 16
#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
u16 tclass, u32 perms, u32 *out_retained), u32 events,
u32 ssid, u32 tsid, u16 tclass, u32 perms);
/* Exported to selinuxfs */
int avc_get_hash_stats(char *page);
extern unsigned int avc_cache_threshold;
#ifdef FLASK_AVC_STATS
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
#endif
#endif /* _FLASK_AVC_H_ */
+14
View File
@@ -0,0 +1,14 @@
/*
* Access vector cache interface for the security server.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
#ifndef _FLASK_AVC_SS_H_
#define _FLASK_AVC_SS_H_
#include "flask.h"
int avc_ss_reset(u32 seqno);
#endif /* _FLASK_AVC_SS_H_ */
+14
View File
@@ -0,0 +1,14 @@
/* This file is automatically generated. Do not edit. */
/*
* Security object class definitions
*/
S_("null")
S_("xen")
S_("domain")
S_("hvm")
S_("mmu")
S_("resource")
S_("shadow")
S_("event")
S_("grant")
S_("security")
@@ -0,0 +1 @@
/* This file is automatically generated. Do not edit. */
+22
View File
@@ -0,0 +1,22 @@
/*
* Interface to booleans in the security server. This is exported
* for the selinuxfs.
*
* Author: Karl MacMillan <kmacmillan@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 _FLASK_CONDITIONAL_H_
#define _FLASK_CONDITIONAL_H_
int security_get_bools(int *len, char ***names, int **values);
int security_set_bools(int len, int *values);
int security_get_bool_value(int bool);
#endif
+36
View File
@@ -0,0 +1,36 @@
/* This file is automatically generated. Do not edit. */
#ifndef _FLASK_FLASK_H_
#define _FLASK_FLASK_H_
/*
* Security object class definitions
*/
#define SECCLASS_XEN 1
#define SECCLASS_DOMAIN 2
#define SECCLASS_HVM 3
#define SECCLASS_MMU 4
#define SECCLASS_RESOURCE 5
#define SECCLASS_SHADOW 6
#define SECCLASS_EVENT 7
#define SECCLASS_GRANT 8
#define SECCLASS_SECURITY 9
/*
* Security identifier indices for initial entities
*/
#define SECINITSID_XEN 1
#define SECINITSID_DOM0 2
#define SECINITSID_DOMU 3
#define SECINITSID_DOMIO 4
#define SECINITSID_DOMXEN 5
#define SECINITSID_UNLABELED 6
#define SECINITSID_SECURITY 7
#define SECINITSID_IOPORT 8
#define SECINITSID_IOMEM 9
#define SECINITSID_VCPU 10
#define SECINITSID_VIRQ 11
#define SECINITSID_PIRQ 12
#define SECINITSID_NUM 12
#endif
@@ -0,0 +1,18 @@
/* This file is automatically generated. Do not edit. */
static char *initial_sid_to_string[] =
{
"null",
"xen",
"dom0",
"domU",
"domio",
"domxen",
"unlabeled",
"security",
"ioport",
"iomem",
"vcpu",
"virq",
"pirq",
};
+33
View File
@@ -0,0 +1,33 @@
/*
* NSA Security-Enhanced Linux (SELinux) security module
*
* This file contains the Flask security data structures for xen objects.
*
* Author(s): George Coker, <gscoker@alpha.ncsc.mil>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#ifndef _FLASK_OBJSEC_H_
#define _FLASK_OBJSEC_H_
#include <xen/sched.h>
#include "flask.h"
#include "avc.h"
struct domain_security_struct {
struct domain *d; /* back pointer to domain object */
u32 sid; /* current SID */
u32 create_sid;
};
struct evtchn_security_struct {
struct evtchn *chn; /* back pointer to evtchn object */
u32 sid; /* current SID */
};
extern unsigned int selinux_checkreqprot;
#endif /* _FLASK_OBJSEC_H_ */
+83
View File
@@ -0,0 +1,83 @@
/*
* Security server interface.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#ifndef _FLASK_SECURITY_H_
#define _FLASK_SECURITY_H_
#include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
#define SECSID_WILD 0xffffffff /* wildcard SID */
#define SECCLASS_NULL 0x0000 /* no class */
#define FLASK_MAGIC 0xf97cff8c
/* Identify specific policy version changes */
#define POLICYDB_VERSION_BASE 15
#define POLICYDB_VERSION_BOOL 16
#define POLICYDB_VERSION_IPV6 17
#define POLICYDB_VERSION_NLCLASS 18
#define POLICYDB_VERSION_VALIDATETRANS 19
#define POLICYDB_VERSION_MLS 19
#define POLICYDB_VERSION_AVTAB 20
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB
#ifdef FLASK_BOOTPARAM
extern int flask_enabled;
#else
#define flask_enabled 1
#endif
extern int flask_mls_enabled;
int security_load_policy(void * data, size_t len);
struct av_decision {
u32 allowed;
u32 decided;
u32 auditallow;
u32 auditdeny;
u32 seqno;
};
int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid);
int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(char *scontext, u32 scontext_len, u32 *out_sid);
int security_context_to_sid_default(char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid);
int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel);
int security_pirq_sid(int pirq, u32 *out_sid);
int security_virq_sid(int virq, u32 *out_sid);
int security_vcpu_sid(int vcpu, u32 *out_sid);
int security_iomem_sid(unsigned long, u32 *out_sid);
int security_ioport_sid(u32 ioport, u32 *out_sid);
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);
#endif /* _FLASK_SECURITY_H_ */
+11
View File
@@ -0,0 +1,11 @@
obj-y += ebitmap.o
obj-y += hashtab.o
obj-y += symtab.o
obj-y += sidtab.o
obj-y += avtab.o
obj-y += policydb.o
obj-y += services.o
obj-y += conditional.o
obj-y += mls.o
CFLAGS += -I../include
+471
View File
@@ -0,0 +1,471 @@
/*
* 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <asm/byteorder.h>
#include <xen/types.h>
#include <xen/xmalloc.h>
#include <xen/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 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 = xmalloc(struct avtab_node);
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;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
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 &&
(specified & cur->key.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;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
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 &&
(specified & cur->key.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 hvalue;
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
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->key.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 hvalue;
struct avtab_node *cur;
u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
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->key.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;
specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
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->key.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;
xfree(temp);
}
h->htable[i] = NULL;
}
xfree(h->htable);
h->htable = NULL;
}
int avtab_init(struct avtab *h)
{
int i;
h->htable = (void *)xmalloc_array(struct avtab_node, 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);
}
static uint16_t spec_order[] = {
AVTAB_ALLOWED,
AVTAB_AUDITDENY,
AVTAB_AUDITALLOW,
AVTAB_TRANSITION,
AVTAB_CHANGE,
AVTAB_MEMBER
};
int avtab_read_item(void *fp, u32 vers, struct avtab *a,
int (*insertf)(struct avtab *a, struct avtab_key *k,
struct avtab_datum *d, void *p), void *p)
{
__le16 buf16[4];
u16 enabled;
__le32 buf32[7];
u32 items, items2, val;
struct avtab_key key;
struct avtab_datum datum;
int i, rc;
memset(&key, 0, sizeof(struct avtab_key));
memset(&datum, 0, sizeof(struct avtab_datum));
if ( vers < POLICYDB_VERSION_AVTAB )
{
rc = next_entry(buf32, fp, sizeof(u32));
if ( rc < 0 )
{
printk(KERN_ERR "security: avtab: truncated entry\n");
return -1;
}
items2 = le32_to_cpu(buf32[0]);
if ( items2 > ARRAY_SIZE(buf32) )
{
printk(KERN_ERR "security: avtab: entry overflow\n");
return -1;
}
rc = next_entry(buf32, fp, sizeof(u32)*items2);
if ( rc < 0 )
{
printk(KERN_ERR "security: avtab: truncated entry\n");
return -1;
}
items = 0;
val = le32_to_cpu(buf32[items++]);
key.source_type = (u16)val;
if ( key.source_type != val )
{
printk("security: avtab: truncated source type\n");
return -1;
}
val = le32_to_cpu(buf32[items++]);
key.target_type = (u16)val;
if ( key.target_type != val )
{
printk("security: avtab: truncated target type\n");
return -1;
}
val = le32_to_cpu(buf32[items++]);
key.target_class = (u16)val;
if ( key.target_class != val )
{
printk("security: avtab: truncated target class\n");
return -1;
}
val = le32_to_cpu(buf32[items++]);
enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
if ( !(val & (AVTAB_AV | AVTAB_TYPE)) )
{
printk("security: avtab: null entry\n");
return -1;
}
if ( (val & AVTAB_AV) && (val & AVTAB_TYPE) )
{
printk("security: avtab: entry has both access vectors and types\n");
return -1;
}
for ( i = 0; i < sizeof(spec_order)/sizeof(u16); i++ )
{
if ( val & spec_order[i] )
{
key.specified = spec_order[i] | enabled;
datum.data = le32_to_cpu(buf32[items++]);
rc = insertf(a, &key, &datum, p);
if ( rc )
return rc;
}
}
if ( items != items2 ) {
printk("security: avtab: entry only had %d items, expected %d\n",
items2, items);
return -1;
}
return 0;
}
rc = next_entry(buf16, fp, sizeof(u16)*4);
if ( rc < 0 )
{
printk("security: avtab: truncated entry\n");
return -1;
}
items = 0;
key.source_type = le16_to_cpu(buf16[items++]);
key.target_type = le16_to_cpu(buf16[items++]);
key.target_class = le16_to_cpu(buf16[items++]);
key.specified = le16_to_cpu(buf16[items++]);
rc = next_entry(buf32, fp, sizeof(u32));
if ( rc < 0 )
{
printk("security: avtab: truncated entry\n");
return -1;
}
datum.data = le32_to_cpu(*buf32);
return insertf(a, &key, &datum, p);
}
static int avtab_insertf(struct avtab *a, struct avtab_key *k,
struct avtab_datum *d, void *p)
{
return avtab_insert(a, k, d);
}
int avtab_read(struct avtab *a, void *fp, u32 vers)
{
int rc;
__le32 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++ )
{
rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL);
if ( rc )
{
if ( rc == -ENOMEM )
printk(KERN_ERR "security: avtab: out of memory\n");
else if ( rc == -EEXIST )
printk(KERN_ERR "security: avtab: duplicate entry\n");
else
rc = -EINVAL;
goto bad;
}
}
rc = 0;
out:
return rc;
bad:
avtab_destroy(a);
goto out;
}
+85
View 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
struct avtab_key {
u16 source_type; /* source type */
u16 target_type; /* target type */
u16 target_class; /* target object class */
#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_OLD 0x80000000 /* reserved for used in cond_avtab */
#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
u16 specified; /* what field is specified */
};
struct avtab_datum {
u32 data; /* access vector or type value */
};
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);
void avtab_destroy(struct avtab *h);
void avtab_hash_eval(struct avtab *h, char *tag);
int avtab_read_item(void *fp, uint32_t vers, struct avtab *a,
int (*insert)(struct avtab *a, struct avtab_key *k,
struct avtab_datum *d, void *p),
void *p);
int avtab_read(struct avtab *a, void *fp, u32 vers);
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);
struct avtab_node *avtab_search_node_next(struct avtab_node *node,
int specified);
#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_ */
+546
View File
@@ -0,0 +1,546 @@
/* 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <asm/byteorder.h>
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/errno.h>
#include <xen/string.h>
#include <xen/spinlock.h>
#include <xen/xmalloc.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->key.specified &= ~AVTAB_ENABLED;
else
cur->node->key.specified |= AVTAB_ENABLED;
}
for ( cur = node->false_list; cur != NULL; cur = cur->next )
{
/* -1 or 1 */
if ( new_state )
cur->node->key.specified &= ~AVTAB_ENABLED;
else
cur->node->key.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 */
xfree(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;
xfree(cur_expr);
}
cond_av_list_destroy(node->true_list);
cond_av_list_destroy(node->false_list);
xfree(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)
{
xfree(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)
{
xfree(p->bool_val_to_struct);
p->bool_val_to_struct = (struct cond_bool_datum**)
xmalloc_array(struct cond_bool_datum*, p->p_bools.nprim);
if ( !p->bool_val_to_struct )
return -1;
return 0;
}
int cond_destroy_bool(void *key, void *datum, void *p)
{
xfree(key);
xfree(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;
__le32 buf[3];
u32 len;
int rc;
booldatum = xmalloc(struct cond_bool_datum);
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 = xmalloc_array(char, len + 1);
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;
}
struct cond_insertf_data
{
struct policydb *p;
struct cond_av_list *other;
struct cond_av_list *head;
struct cond_av_list *tail;
};
static int cond_insertf(struct avtab *a, struct avtab_key *k,
struct avtab_datum *d, void *ptr)
{
struct cond_insertf_data *data = ptr;
struct policydb *p = data->p;
struct cond_av_list *other = data->other, *list, *cur;
struct avtab_node *node_ptr;
u8 found;
/*
* 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 ( k->specified & AVTAB_TYPE )
{
if ( avtab_search(&p->te_avtab, k) )
{
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, k);
if ( node_ptr )
{
if ( avtab_search_node_next(node_ptr, k->specified) )
{
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.\n");
goto err;
}
}
}
else
{
if ( avtab_search(&p->te_cond_avtab, k) )
{
printk("security: conflicting type rules when adding type rule "
"for true.\n");
goto err;
}
}
}
node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
if ( !node_ptr )
{
printk("security: could not insert rule.");
goto err;
}
list = xmalloc(struct cond_av_list);
if ( !list )
goto err;
memset(list, 0, sizeof(*list));
list->node = node_ptr;
if ( !data->head )
data->head = list;
else
data->tail->next = list;
data->tail = list;
return 0;
err:
cond_av_list_destroy(data->head);
data->head = 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)
{
int i, rc;
__le32 buf[1];
u32 len;
struct cond_insertf_data data;
*ret_list = NULL;
len = 0;
rc = next_entry(buf, fp, sizeof(u32));
if ( rc < 0 )
return -1;
len = le32_to_cpu(buf[0]);
if ( len == 0 )
{
return 0;
}
data.p = p;
data.other = other;
data.head = NULL;
data.tail = NULL;
for ( i = 0; i < len; i++ )
{
rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf,
&data);
if ( rc )
return rc;
}
*ret_list = data.head;
return 0;
}
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)
{
__le32 buf[2];
u32 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 = xmalloc(struct cond_expr);
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) )
{
xfree(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;
__le32 buf[1];
u32 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 = xmalloc(struct cond_node);
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);
p->cond_list = NULL;
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); node != NULL;
node = avtab_search_node_next(node, key->specified) )
{
if ( (u16) (AVTAB_ALLOWED|AVTAB_ENABLED) ==
(node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) )
avd->allowed |= node->datum.data;
if ( (u16) (AVTAB_AUDITDENY|AVTAB_ENABLED) ==
(node->key.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 &= node->datum.data;
if ( (u16) (AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
(node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)) )
avd->auditallow |= node->datum.data;
}
return;
}
+77
View 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
View 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_ */
+110
View File
@@ -0,0 +1,110 @@
/*
* 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>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.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 (!flask_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 (!flask_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 (!flask_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_ */
+328
View File
@@ -0,0 +1,328 @@
/*
* Implementation of the extensible bitmap type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <asm/byteorder.h>
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/errno.h>
#include <xen/spinlock.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 = xmalloc(struct ebitmap_node);
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;
xfree(n);
}
}
return 0;
}
prev = n;
n = n->next;
}
if ( !value )
return 0;
new = xmalloc(struct ebitmap_node);
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;
xfree(temp);
}
e->highbit = 0;
e->node = NULL;
return;
}
int ebitmap_read(struct ebitmap *e, void *fp)
{
int rc;
struct ebitmap_node *n, *l;
__le32 buf[3];
u32 mapsize, count, i;
__le64 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 = xmalloc(struct ebitmap_node);
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:
xfree(n);
bad:
if ( !rc )
rc = -EINVAL;
ebitmap_destroy(e);
goto out;
}
+79
View File
@@ -0,0 +1,79 @@
/*
* 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 unsigned int ebitmap_start(struct ebitmap *e,
struct ebitmap_node **n)
{
*n = e->node;
return ebitmap_startbit(e);
}
static inline void ebitmap_init(struct ebitmap *e)
{
memset(e, 0, sizeof(*e));
}
static inline unsigned int ebitmap_next(struct ebitmap_node **n,
unsigned int bit)
{
if ( (bit == ((*n)->startbit + MAPSIZE - 1)) && (*n)->next )
{
*n = (*n)->next;
return (*n)->startbit;
}
return (bit+1);
}
static inline int ebitmap_node_get_bit(struct ebitmap_node * n,
unsigned int bit)
{
if ( n->map & (MAPBIT << (bit - n->startbit)) )
return 1;
return 0;
}
#define ebitmap_for_each_bit(e, n, bit) \
for ( bit = ebitmap_start(e, &n); bit < ebitmap_length(e); \
bit = ebitmap_next(&n, bit) ) \
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_ */
+181
View File
@@ -0,0 +1,181 @@
/*
* Implementation of the hash table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/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 = xmalloc(struct hashtab);
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 = (void *)xmalloc_array(struct hashtab_node, size);
if ( p->htable == NULL )
{
xfree(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 = xmalloc(struct hashtab_node);
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;
xfree(temp);
}
h->htable[i] = NULL;
}
xfree(h->htable);
h->htable = NULL;
xfree(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;
}
+85
View File
@@ -0,0 +1,85 @@
/*
* 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 */
+612
View File
@@ -0,0 +1,612 @@
/*
* 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/string.h>
#include <xen/errno.h>
#include "sidtab.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;
struct ebitmap_node *node;
if (!flask_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]);
ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
{
if ( ebitmap_node_get_bit(node, i) )
{
if ( range )
{
range++;
continue;
}
len += strlen(policydb.p_cat_val_to_name[i]) + 1;
range++;
}
else
{
if ( range > 1 )
len += strlen(policydb.p_cat_val_to_name[i - 1]) + 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 - 1]) + 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;
struct ebitmap_node *node;
if ( !flask_mls_enabled )
return;
scontextp = *scontext;
*scontextp = ':';
scontextp++;
for ( l = 0; l < 2; l++ )
{
range = 0;
wrote_sep = 0;
strlcpy(scontextp,
policydb.p_sens_val_to_name[context->range.level[l].sens - 1],
strlen(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 */
ebitmap_for_each_bit(&context->range.level[l].cat, node, i)
{
if ( ebitmap_node_get_bit(node, i) )
{
if ( range )
{
range++;
continue;
}
if ( !wrote_sep )
{
*scontextp++ = ':';
wrote_sep = 1;
}
else
*scontextp++ = ',';
strlcpy(scontextp, policydb.p_cat_val_to_name[i],
strlen(policydb.p_cat_val_to_name[i]));
scontextp += strlen(policydb.p_cat_val_to_name[i]);
range++;
}
else
{
if ( range > 1 )
{
if ( range > 2 )
*scontextp++ = '.';
else
*scontextp++ = ',';
strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
strlen(policydb.p_cat_val_to_name[i - 1]));
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
}
range = 0;
}
}
/* Handle case where last category is the end of range */
if ( range > 1 )
{
if ( range > 2 )
*scontextp++ = '.';
else
*scontextp++ = ',';
strlcpy(scontextp, policydb.p_cat_val_to_name[i - 1],
strlen(policydb.p_cat_val_to_name[i - 1]));
scontextp += strlen(policydb.p_cat_val_to_name[i - 1]);
}
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;
struct ebitmap_node *node;
int i, l;
if ( !flask_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;
ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
{
if ( ebitmap_node_get_bit(node, i) )
{
if ( i > p->p_cats.nprim )
return 0;
if ( !ebitmap_get_bit(&levdatum->level->cat, i) )
/*
* 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;
}
/*
* 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;
}
/*
* 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.
*
* If a def_sid is provided and no MLS field is present,
* copy the MLS field of the associated default context.
* Used for upgraded to MLS systems where objects may lack
* MLS fields.
*
* Policy read-lock must be held for sidtab lookup.
*
*/
int mls_context_to_sid(char oldc, char **scontext, struct context *context,
struct sidtab *s, u32 def_sid)
{
char delim;
char *scontextp, *p, *rngptr;
struct level_datum *levdatum;
struct cat_datum *catdatum, *rngdatum;
int l, rc = -EINVAL;
if ( !flask_mls_enabled )
return 0;
/*
* No MLS component to the security context, try and map to
* default if provided.
*/
if ( !oldc )
{
struct context *defcon;
if ( def_sid == SECSID_NULL )
goto out;
defcon = sidtab_search(s, def_sid);
if ( !defcon )
goto out;
rc = mls_copy_context(context, defcon);
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 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 ( flask_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;
struct ebitmap_node *node;
int l, i;
if ( !flask_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);
ebitmap_for_each_bit(&c->range.level[l].cat, node, i)
{
if ( ebitmap_node_get_bit(node, i) )
{
int rc;
catdatum = hashtab_search(newp->p_cats.table,
oldp->p_cat_val_to_name[i]);
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 ( !flask_mls_enabled )
return 0;
switch ( specified )
{
case AVTAB_TRANSITION:
if ( tclass == SECCLASS_DOMAIN )
{
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_DOMAIN )
/* 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;
}
+37
View File
@@ -0,0 +1,37 @@
/*
* 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,
struct sidtab *s, u32 def_sid);
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 */
+58
View File
@@ -0,0 +1,58 @@
/*
* 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#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 ( !flask_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 ( !flask_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_ */
File diff suppressed because it is too large. Load diff
+257
View File
@@ -0,0 +1,257 @@
/*
* 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.
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#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 */
int pirq;
int virq;
int vcpu;
u32 ioport;
unsigned long iomem;
} u;
struct context context[2]; /* security context(s) */
u32 sid[2]; /* SID(s) */
struct ocontext *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_PIRQ 1 /* physical irqs */
#define OCON_VIRQ 2 /* virtual irqs */
#define OCON_VCPU 3 /* virtual cpus */
#define OCON_IOPORT 4 /* io ports */
#define OCON_IOMEM 5 /* io memory */
#define OCON_DUMMY 6
#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];
/* range transitions */
struct range_trans *range_tr;
/* type -> attribute reverse mapping */
struct ebitmap *type_attr_map;
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 FLASK_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_ */
File diff suppressed because it is too large. Load diff
+15
View 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_ */
+327
View File
@@ -0,0 +1,327 @@
/*
* Implementation of the SID table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/errno.h>
#include <xen/spinlock.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 = (void *)xmalloc_array(struct sidtab_node, SIDTAB_SIZE);
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 = xmalloc(struct sidtab_node);
if ( newnode == NULL )
{
rc = -ENOMEM;
goto out;
}
newnode->sid = sid;
if ( context_cpy(&newnode->context, context) )
{
xfree(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);
xfree(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);
xfree(temp);
}
s->htable[i] = NULL;
}
xfree(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);
}
+53
View File
@@ -0,0 +1,53 @@
/*
* A security identifier table (sidtab) is a hash table
* of security context structures indexed by SID value.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#ifndef _SS_SIDTAB_H_
#define _SS_SIDTAB_H_
#include "context.h"
#include <xen/spinlock.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_ */
+47
View File
@@ -0,0 +1,47 @@
/*
* Implementation of the symbol table type.
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
#include <xen/lib.h>
#include <xen/xmalloc.h>
#include <xen/string.h>
#include <xen/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
View 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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.