mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Xen Security Modules: FLASK
Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
This commit is contained in:
1 parent
d046f361dc
commit
b1ed041464
44 files changed
+10814
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -3,3 +3,5 @@ obj-y += xsm_policy.o
|
||||
ifeq ($(XSM_ENABLE),y)
|
||||
obj-y += dummy.o
|
||||
endif
|
||||
|
||||
subdir-$(FLASK_ENABLE) += flask
|
||||
@@ -0,0 +1,7 @@
|
||||
obj-y += avc.o
|
||||
obj-y += hooks.o
|
||||
obj-y += flask_op.o
|
||||
|
||||
subdir-y += ss
|
||||
|
||||
CFLAGS += -I./include
|
||||
@@ -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(¬if_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(¬if_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
@@ -0,0 +1 @@
|
||||
/* This file is automatically generated. Do not edit. */
|
||||
@@ -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")
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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. */
|
||||
@@ -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
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
|
||||