Mailing List Archive

[xen-unstable] Xen Security Modules: FLASK
# HG changeset patch
# User kfraser@localhost.localdomain
# Date 1188556278 -3600
# Node ID 6c8c934b235c39f821efdfe6a2af7d44e4e35aab
# Parent 96f64f4c42f043e3af2db369f4b9bdb9fcef017b
Xen Security Modules: FLASK
Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
---
Config.mk | 8
xen/Rules.mk | 4
xen/common/vsprintf.c | 236 +++
xen/include/public/xsm/flask_op.h | 45
xen/include/xen/lib.h | 4
xen/xsm/Makefile | 2
xen/xsm/flask/Makefile | 7
xen/xsm/flask/avc.c | 817 +++++++++++
xen/xsm/flask/flask_op.c | 1079 +++++++++++++++
xen/xsm/flask/hooks.c | 1159 ++++++++++++++++
xen/xsm/flask/include/av_inherit.h | 1
xen/xsm/flask/include/av_perm_to_string.h | 99 +
xen/xsm/flask/include/av_permissions.h | 108 +
xen/xsm/flask/include/avc.h | 106 +
xen/xsm/flask/include/avc_ss.h | 14
xen/xsm/flask/include/class_to_string.h | 14
xen/xsm/flask/include/common_perm_to_string.h | 1
xen/xsm/flask/include/conditional.h | 22
xen/xsm/flask/include/flask.h | 36
xen/xsm/flask/include/initial_sid_to_string.h | 18
xen/xsm/flask/include/objsec.h | 33
xen/xsm/flask/include/security.h | 83 +
xen/xsm/flask/ss/Makefile | 11
xen/xsm/flask/ss/avtab.c | 471 ++++++
xen/xsm/flask/ss/avtab.h | 85 +
xen/xsm/flask/ss/conditional.c | 546 +++++++
xen/xsm/flask/ss/conditional.h | 77 +
xen/xsm/flask/ss/constraint.h | 61
xen/xsm/flask/ss/context.h | 110 +
xen/xsm/flask/ss/ebitmap.c | 328 ++++
xen/xsm/flask/ss/ebitmap.h | 79 +
xen/xsm/flask/ss/hashtab.c | 181 ++
xen/xsm/flask/ss/hashtab.h | 85 +
xen/xsm/flask/ss/mls.c | 612 ++++++++
xen/xsm/flask/ss/mls.h | 37
xen/xsm/flask/ss/mls_types.h | 58
xen/xsm/flask/ss/policydb.c | 1798 ++++++++++++++++++++++++++
xen/xsm/flask/ss/policydb.h | 257 +++
xen/xsm/flask/ss/services.c | 1657 +++++++++++++++++++++++
xen/xsm/flask/ss/services.h | 15
xen/xsm/flask/ss/sidtab.c | 327 ++++
xen/xsm/flask/ss/sidtab.h | 53
xen/xsm/flask/ss/symtab.c | 47
xen/xsm/flask/ss/symtab.h | 23
44 files changed, 10814 insertions(+)

diff -r 96f64f4c42f0 -r 6c8c934b235c Config.mk
--- a/Config.mk Fri Aug 31 11:21:35 2007 +0100
+++ b/Config.mk Fri Aug 31 11:31:18 2007 +0100
@@ -81,6 +81,14 @@ CFLAGS += $(foreach i, $(EXTRA_INCLUDES)
# 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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/Rules.mk
--- a/xen/Rules.mk Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/Rules.mk Fri Aug 31 11:31:18 2007 +0100
@@ -58,6 +58,10 @@ ALL_OBJS-y += $(BASEDIR)/a

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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/common/vsprintf.c
--- a/xen/common/vsprintf.c Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/common/vsprintf.c Fri Aug 31 11:31:18 2007 +0100
@@ -513,6 +513,223 @@ EXPORT_SYMBOL(vscnprintf);
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
* @size: The size of the buffer, including the trailing null space
@@ -561,6 +778,25 @@ int scnprintf(char * buf, size_t size, c
}
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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/include/public/xsm/flask_op.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/public/xsm/flask_op.h Fri Aug 31 11:31:18 2007 +0100
@@ -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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/include/xen/lib.h
--- a/xen/include/xen/lib.h Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/include/xen/lib.h Fri Aug 31 11:31:18 2007 +0100
@@ -75,6 +75,10 @@ extern int scnprintf(char * buf, size_t
__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);
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/Makefile
--- a/xen/xsm/Makefile Fri Aug 31 11:21:35 2007 +0100
+++ b/xen/xsm/Makefile Fri Aug 31 11:31:18 2007 +0100
@@ -3,3 +3,5 @@ ifeq ($(XSM_ENABLE),y)
ifeq ($(XSM_ENABLE),y)
obj-y += dummy.o
endif
+
+subdir-$(FLASK_ENABLE) += flask
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/Makefile Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,7 @@
+obj-y += avc.o
+obj-y += hooks.o
+obj-y += flask_op.o
+
+subdir-y += ss
+
+CFLAGS += -I./include
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/avc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/avc.c Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,817 @@
+/*
+ * Implementation of the kernel access vector cache (AVC).
+ *
+ * Authors: Stephen Smalley, <sds@epoch.ncsc.mil>
+ * James Morris <jmorris@redhat.com>
+ *
+ * Update: KaiGai, Kohei <kaigai@ak.jp.nec.com>
+ * Replaced the avc_lock spinlock by RCU.
+ *
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+/* Ported to Xen 3.0, George Coker, <gscoker@alpha.ncsc.mil> */
+
+#include <xen/lib.h>
+#include <xen/xmalloc.h>
+#include <xen/types.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+#include <xen/prefetch.h>
+#include <xen/kernel.h>
+#include <xen/sched.h>
+#include <xen/init.h>
+#include <xen/rcupdate.h>
+#include <asm/atomic.h>
+#include <asm/current.h>
+
+#include "avc.h"
+#include "avc_ss.h"
+
+static const struct av_perm_to_string
+{
+ u16 tclass;
+ u32 value;
+ const char *name;
+} av_perm_to_string[] = {
+#define S_(c, v, s) { c, v, s },
+#include "av_perm_to_string.h"
+#undef S_
+};
+
+static const char *class_to_string[] = {
+#define S_(s) s,
+#include "class_to_string.h"
+#undef S_
+};
+
+#define TB_(s) static const char * s [] = {
+#define TE_(s) };
+#define S_(s) s,
+#include "common_perm_to_string.h"
+#undef TB_
+#undef TE_
+#undef S_
+
+static const struct av_inherit
+{
+ u16 tclass;
+ const char **common_pts;
+ u32 common_base;
+} av_inherit[] = {
+#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
+#include "av_inherit.h"
+#undef S_
+};
+
+#define AVC_CACHE_SLOTS 512
+#define AVC_DEF_CACHE_THRESHOLD 512
+#define AVC_CACHE_RECLAIM 16
+
+#ifdef FLASK_AVC_STATS
+#define avc_cache_stats_incr(field) \
+do { \
+ __get_cpu_var(avc_cache_stats).field++; \
+} while (0)
+#else
+#define avc_cache_stats_incr(field) do {} while (0)
+#endif
+
+struct avc_entry {
+ u32 ssid;
+ u32 tsid;
+ u16 tclass;
+ struct av_decision avd;
+ atomic_t used; /* used recently */
+};
+
+struct avc_node {
+ struct avc_entry ae;
+ struct list_head list;
+ struct rcu_head rhead;
+};
+
+struct avc_cache {
+ struct list_head slots[AVC_CACHE_SLOTS];
+ spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
+ atomic_t lru_hint; /* LRU hint for reclaim scan */
+ atomic_t active_nodes;
+ u32 latest_notif; /* latest revocation notification */
+};
+
+struct avc_callback_node {
+ int (*callback) (u32 event, u32 ssid, u32 tsid,
+ u16 tclass, u32 perms,
+ u32 *out_retained);
+ u32 events;
+ u32 ssid;
+ u32 tsid;
+ u16 tclass;
+ u32 perms;
+ struct avc_callback_node *next;
+};
+
+/* Exported via Flask hypercall */
+unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
+
+#ifdef FLASK_AVC_STATS
+DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
+#endif
+
+static struct avc_cache avc_cache;
+static struct avc_callback_node *avc_callbacks;
+
+static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
+{
+ return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
+}
+
+/**
+ * avc_dump_av - Display an access vector in human-readable form.
+ * @tclass: target security class
+ * @av: access vector
+ */
+static void avc_dump_av(u16 tclass, u32 av)
+{
+ const char **common_pts = NULL;
+ u32 common_base = 0;
+ int i, i2, perm;
+
+ if ( av == 0 )
+ {
+ printk(" null");
+ return;
+ }
+
+ for ( i = 0; i < ARRAY_SIZE(av_inherit); i++ )
+ {
+ if (av_inherit[i].tclass == tclass)
+ {
+ common_pts = av_inherit[i].common_pts;
+ common_base = av_inherit[i].common_base;
+ break;
+ }
+ }
+
+ printk(" {");
+ i = 0;
+ perm = 1;
+ while ( perm < common_base )
+ {
+ if (perm & av)
+ {
+ printk(" %s", common_pts[i]);
+ av &= ~perm;
+ }
+ i++;
+ perm <<= 1;
+ }
+
+ while ( i < sizeof(av) * 8 )
+ {
+ if ( perm & av )
+ {
+ for ( i2 = 0; i2 < ARRAY_SIZE(av_perm_to_string); i2++ )
+ {
+ if ( (av_perm_to_string[i2].tclass == tclass) &&
+ (av_perm_to_string[i2].value == perm) )
+ break;
+ }
+ if ( i2 < ARRAY_SIZE(av_perm_to_string) )
+ {
+ printk(" %s", av_perm_to_string[i2].name);
+ av &= ~perm;
+ }
+ }
+ i++;
+ perm <<= 1;
+ }
+
+ if ( av )
+ printk(" 0x%x", av);
+
+ printk(" }");
+}
+
+/**
+ * avc_dump_query - Display a SID pair and a class in human-readable form.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ */
+static void avc_dump_query(u32 ssid, u32 tsid, u16 tclass)
+{
+ int rc;
+ char *scontext;
+ u32 scontext_len;
+
+ rc = security_sid_to_context(ssid, &scontext, &scontext_len);
+ if ( rc )
+ printk("ssid=%d", ssid);
+ else
+ {
+ printk("scontext=%s", scontext);
+ xfree(scontext);
+ }
+
+ rc = security_sid_to_context(tsid, &scontext, &scontext_len);
+ if ( rc )
+ printk(" tsid=%d", tsid);
+ else
+ {
+ printk(" tcontext=%s", scontext);
+ xfree(scontext);
+ }
+ printk("\n");
+ printk("tclass=%s", class_to_string[tclass]);
+}
+
+/**
+ * avc_init - Initialize the AVC.
+ *
+ * Initialize the access vector cache.
+ */
+void __init avc_init(void)
+{
+ int i;
+
+ for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+ {
+ INIT_LIST_HEAD(&avc_cache.slots[i]);
+ spin_lock_init(&avc_cache.slots_lock[i]);
+ }
+ atomic_set(&avc_cache.active_nodes, 0);
+ atomic_set(&avc_cache.lru_hint, 0);
+
+ printk("AVC INITIALIZED\n");
+}
+
+int avc_get_hash_stats(char *page)
+{
+ int i, chain_len, max_chain_len, slots_used;
+ struct avc_node *node;
+
+ rcu_read_lock();
+
+ slots_used = 0;
+ max_chain_len = 0;
+ for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+ {
+ if ( !list_empty(&avc_cache.slots[i]) )
+ {
+ slots_used++;
+ chain_len = 0;
+ list_for_each_entry_rcu(node, &avc_cache.slots[i], list)
+ chain_len++;
+ if ( chain_len > max_chain_len )
+ max_chain_len = chain_len;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
+ "longest chain: %d\n",
+ atomic_read(&avc_cache.active_nodes),
+ slots_used, AVC_CACHE_SLOTS, max_chain_len);
+}
+
+static void avc_node_free(struct rcu_head *rhead)
+{
+ struct avc_node *node = container_of(rhead, struct avc_node, rhead);
+ xfree(node);
+ avc_cache_stats_incr(frees);
+}
+
+static void avc_node_delete(struct avc_node *node)
+{
+ list_del_rcu(&node->list);
+ call_rcu(&node->rhead, avc_node_free);
+ atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_kill(struct avc_node *node)
+{
+ xfree(node);
+ avc_cache_stats_incr(frees);
+ atomic_dec(&avc_cache.active_nodes);
+}
+
+static void avc_node_replace(struct avc_node *new, struct avc_node *old)
+{
+ list_replace_rcu(&old->list, &new->list);
+ call_rcu(&old->rhead, avc_node_free);
+ atomic_dec(&avc_cache.active_nodes);
+}
+
+static inline int avc_reclaim_node(void)
+{
+ struct avc_node *node;
+ int hvalue, try, ecx;
+ unsigned long flags;
+
+ for ( try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++ )
+ {
+ atomic_inc(&avc_cache.lru_hint);
+ hvalue = atomic_read(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1);
+
+ spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flags);
+
+ list_for_each_entry(node, &avc_cache.slots[hvalue], list)
+ {
+ if ( atomic_dec_and_test(&node->ae.used) )
+ {
+ /* Recently Unused */
+ avc_node_delete(node);
+ avc_cache_stats_incr(reclaims);
+ ecx++;
+ if ( ecx >= AVC_CACHE_RECLAIM )
+ {
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+ goto out;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
+ }
+out:
+ return ecx;
+}
+
+static struct avc_node *avc_alloc_node(void)
+{
+ struct avc_node *node;
+
+ node = xmalloc(struct avc_node);
+ if (!node)
+ goto out;
+
+ memset(node, 0, sizeof(*node));
+ INIT_RCU_HEAD(&node->rhead);
+ INIT_LIST_HEAD(&node->list);
+ atomic_set(&node->ae.used, 1);
+ avc_cache_stats_incr(allocations);
+
+ atomic_inc(&avc_cache.active_nodes);
+ if ( atomic_read(&avc_cache.active_nodes) > avc_cache_threshold )
+ avc_reclaim_node();
+
+out:
+ return node;
+}
+
+static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+ node->ae.ssid = ssid;
+ node->ae.tsid = tsid;
+ node->ae.tclass = tclass;
+ memcpy(&node->ae.avd, &ae->avd, sizeof(node->ae.avd));
+}
+
+static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
+{
+ struct avc_node *node, *ret = NULL;
+ int hvalue;
+
+ hvalue = avc_hash(ssid, tsid, tclass);
+ list_for_each_entry_rcu(node, &avc_cache.slots[hvalue], list)
+ {
+ if ( ssid == node->ae.ssid && tclass == node->ae.tclass &&
+ tsid == node->ae.tsid )
+ {
+ ret = node;
+ break;
+ }
+ }
+
+ if ( ret == NULL )
+ {
+ /* cache miss */
+ goto out;
+ }
+
+ /* cache hit */
+ if ( atomic_read(&ret->ae.used) != 1 )
+ atomic_set(&ret->ae.used, 1);
+out:
+ return ret;
+}
+
+/**
+ * avc_lookup - Look up an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ *
+ * Look up an AVC entry that is valid for the
+ * @requested permissions between the SID pair
+ * (@ssid, @tsid), interpreting the permissions
+ * based on @tclass. If a valid AVC entry exists,
+ * then this function return the avc_node.
+ * Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass, u32 requested)
+{
+ struct avc_node *node;
+
+ avc_cache_stats_incr(lookups);
+ node = avc_search_node(ssid, tsid, tclass);
+
+ if ( node && ((node->ae.avd.decided & requested) == requested) )
+ {
+ avc_cache_stats_incr(hits);
+ goto out;
+ }
+
+ node = NULL;
+ avc_cache_stats_incr(misses);
+out:
+ return node;
+}
+
+static int avc_latest_notif_update(int seqno, int is_insert)
+{
+ int ret = 0;
+ static DEFINE_SPINLOCK(notif_lock);
+ unsigned long flag;
+
+ spin_lock_irqsave(&notif_lock, flag);
+ if ( is_insert )
+ {
+ if ( seqno < avc_cache.latest_notif )
+ {
+ printk(KERN_WARNING "avc: seqno %d < latest_notif %d\n",
+ seqno, avc_cache.latest_notif);
+ ret = -EAGAIN;
+ }
+ }
+ else
+ {
+ if ( seqno > avc_cache.latest_notif )
+ avc_cache.latest_notif = seqno;
+ }
+ spin_unlock_irqrestore(&notif_lock, flag);
+
+ return ret;
+}
+
+/**
+ * avc_insert - Insert an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @ae: AVC entry
+ *
+ * Insert an AVC entry for the SID pair
+ * (@ssid, @tsid) and class @tclass.
+ * The access vectors and the sequence number are
+ * normally provided by the security server in
+ * response to a security_compute_av() call. If the
+ * sequence number @ae->avd.seqno is not less than the latest
+ * revocation notification, then the function copies
+ * the access vectors into a cache entry, returns
+ * avc_node inserted. Otherwise, this function returns NULL.
+ */
+static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct avc_entry *ae)
+{
+ struct avc_node *pos, *node = NULL;
+ int hvalue;
+ unsigned long flag;
+
+ if ( avc_latest_notif_update(ae->avd.seqno, 1) )
+ goto out;
+
+ node = avc_alloc_node();
+ if ( node )
+ {
+ hvalue = avc_hash(ssid, tsid, tclass);
+ avc_node_populate(node, ssid, tsid, tclass, ae);
+
+ spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+ list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
+ {
+ if ( pos->ae.ssid == ssid && pos->ae.tsid == tsid &&
+ pos->ae.tclass == tclass )
+ {
+ avc_node_replace(node, pos);
+ goto found;
+ }
+ }
+ list_add_rcu(&node->list, &avc_cache.slots[hvalue]);
+found:
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+ }
+out:
+ return node;
+}
+
+/**
+ * avc_audit - Audit the granting or denial of permissions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ * @result: result from avc_has_perm_noaudit
+ * @a: auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy. This function is typically called by
+ * avc_has_perm() after a permission check, but can also be
+ * called directly by callers who use avc_has_perm_noaudit()
+ * in order to separate the permission check from the auditing.
+ * For example, this separation is useful when the permission check must
+ * be performed under a lock, to allow the lock to be released
+ * before calling the auditing code.
+ */
+void avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+ struct av_decision *avd, int result, struct avc_audit_data *a)
+{
+ struct domain *d = current->domain;
+ u32 denied, audited;
+
+ denied = requested & ~avd->allowed;
+ if ( denied )
+ {
+ audited = denied;
+ if ( !(audited & avd->auditdeny) )
+ return;
+ }
+ else if ( result )
+ {
+ audited = denied = requested;
+ }
+ else
+ {
+ audited = requested;
+ if ( !(audited & avd->auditallow) )
+ return;
+ }
+
+ printk("avc: %s ", denied ? "denied" : "granted");
+ avc_dump_av(tclass, audited);
+ printk(" for ");
+
+ if ( a && a->d )
+ d = a->d;
+ if ( d )
+ printk("domid=%d", d->domain_id);
+
+ printk("\n");
+ avc_dump_query(ssid, tsid, tclass);
+ printk("\n");
+
+}
+
+/**
+ * avc_add_callback - Register a callback for security events.
+ * @callback: callback function
+ * @events: security events
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions
+ *
+ * Register a callback function for events in the set @events
+ * related to the SID pair (@ssid, @tsid) and
+ * and the permissions @perms, interpreting
+ * @perms based on @tclass. Returns %0 on success or
+ * -%ENOMEM if insufficient memory exists to add the callback.
+ */
+int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, u16 tclass,
+ u32 perms, u32 *out_retained), u32 events, u32 ssid, u32 tsid,
+ u16 tclass, u32 perms)
+{
+ struct avc_callback_node *c;
+ int rc = 0;
+
+ c = xmalloc(struct avc_callback_node);
+ if ( !c )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ c->callback = callback;
+ c->events = events;
+ c->ssid = ssid;
+ c->tsid = tsid;
+ c->perms = perms;
+ c->next = avc_callbacks;
+ avc_callbacks = c;
+out:
+ return rc;
+}
+
+static inline int avc_sidcmp(u32 x, u32 y)
+{
+ return (x == y || x == SECSID_WILD || y == SECSID_WILD);
+}
+
+/**
+ * avc_update_node Update an AVC entry
+ * @event : Updating event
+ * @perms : Permission mask bits
+ * @ssid,@tsid,@tclass : identifier of an AVC entry
+ *
+ * if a valid AVC entry doesn't exist,this function returns -ENOENT.
+ * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
+ * otherwise, this function update the AVC entry. The original AVC-entry object
+ * will release later by RCU.
+ */
+static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass)
+{
+ int hvalue, rc = 0;
+ unsigned long flag;
+ struct avc_node *pos, *node, *orig = NULL;
+
+ node = avc_alloc_node();
+ if ( !node )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ hvalue = avc_hash(ssid, tsid, tclass);
+ spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);
+
+ list_for_each_entry(pos, &avc_cache.slots[hvalue], list)
+ {
+ if ( ssid==pos->ae.ssid && tsid==pos->ae.tsid &&
+ tclass==pos->ae.tclass )
+ {
+ orig = pos;
+ break;
+ }
+ }
+
+ if ( !orig )
+ {
+ rc = -ENOENT;
+ avc_node_kill(node);
+ goto out_unlock;
+ }
+
+ /*
+ * Copy and replace original node.
+ */
+
+ avc_node_populate(node, ssid, tsid, tclass, &orig->ae);
+
+ switch ( event )
+ {
+ case AVC_CALLBACK_GRANT:
+ node->ae.avd.allowed |= perms;
+ break;
+ case AVC_CALLBACK_TRY_REVOKE:
+ case AVC_CALLBACK_REVOKE:
+ node->ae.avd.allowed &= ~perms;
+ break;
+ case AVC_CALLBACK_AUDITALLOW_ENABLE:
+ node->ae.avd.auditallow |= perms;
+ break;
+ case AVC_CALLBACK_AUDITALLOW_DISABLE:
+ node->ae.avd.auditallow &= ~perms;
+ break;
+ case AVC_CALLBACK_AUDITDENY_ENABLE:
+ node->ae.avd.auditdeny |= perms;
+ break;
+ case AVC_CALLBACK_AUDITDENY_DISABLE:
+ node->ae.avd.auditdeny &= ~perms;
+ break;
+ }
+ avc_node_replace(node, orig);
+out_unlock:
+ spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);
+out:
+ return rc;
+}
+
+/**
+ * avc_ss_reset - Flush the cache and revalidate migrated permissions.
+ * @seqno: policy sequence number
+ */
+int avc_ss_reset(u32 seqno)
+{
+ struct avc_callback_node *c;
+ int i, rc = 0;
+ unsigned long flag;
+ struct avc_node *node;
+
+ for ( i = 0; i < AVC_CACHE_SLOTS; i++ )
+ {
+ spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+ list_for_each_entry(node, &avc_cache.slots[i], list)
+ avc_node_delete(node);
+ spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
+ }
+
+ for ( c = avc_callbacks; c; c = c->next )
+ {
+ if ( c->events & AVC_CALLBACK_RESET )
+ {
+ rc = c->callback(AVC_CALLBACK_RESET,
+ 0, 0, 0, 0, NULL);
+ if ( rc )
+ goto out;
+ }
+ }
+
+ avc_latest_notif_update(seqno, 0);
+out:
+ return rc;
+}
+
+/**
+ * avc_has_perm_noaudit - Check permissions but perform no auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @avd: access vector decisions
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache. Return a copy of the decisions
+ * in @avd. Return %0 if all @requested permissions are granted,
+ * -%EACCES if any permissions are denied, or another -errno upon
+ * other errors. This function is typically called by avc_has_perm(),
+ * but may also be called directly to separate permission checking from
+ * auditing, e.g. in cases where a lock must be held for the check but
+ * should be released for the auditing.
+ */
+int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+ struct av_decision *avd)
+{
+ struct avc_node *node;
+ struct avc_entry entry, *p_ae;
+ int rc = 0;
+ u32 denied;
+
+ rcu_read_lock();
+
+ node = avc_lookup(ssid, tsid, tclass, requested);
+ if ( !node )
+ {
+ rcu_read_unlock();
+ rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);
+ if ( rc )
+ goto out;
+ rcu_read_lock();
+ node = avc_insert(ssid,tsid,tclass,&entry);
+ }
+
+ p_ae = node ? &node->ae : &entry;
+
+ if ( avd )
+ memcpy(avd, &p_ae->avd, sizeof(*avd));
+
+ denied = requested & ~(p_ae->avd.allowed);
+
+ if ( !requested || denied )
+ {
+ if ( flask_enforcing )
+ rc = -EACCES;
+ else
+ if ( node )
+ avc_update_node(AVC_CALLBACK_GRANT,requested,
+ ssid,tsid,tclass);
+ }
+
+ rcu_read_unlock();
+out:
+ return rc;
+}
+
+/**
+ * avc_has_perm - Check permissions and perform any appropriate auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @auditdata: auxiliary audit data
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache. Audit the granting or denial of
+ * permissions in accordance with the policy. Return %0 if all @requested
+ * permissions are granted, -%EACCES if any permissions are denied, or
+ * another -errno upon other errors.
+ */
+int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct avc_audit_data *auditdata)
+{
+ struct av_decision avd;
+ int rc;
+
+ rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
+ avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+ return rc;
+}
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/flask_op.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/flask_op.c Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1079 @@
+/*
+ * This file contains the flask_op hypercall and associated functions.
+ *
+ * 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.
+ */
+
+#include <xen/errno.h>
+#include <xsm/xsm.h>
+#include <xen/guest_access.h>
+
+#include <public/xsm/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+#ifdef FLASK_DEVELOP
+int flask_enforcing = 0;
+integer_param("flask_enforcing", flask_enforcing);
+#endif
+
+#ifdef FLASK_BOOTPARAM
+int flask_enabled = 1;
+integer_param("flask_enabled", flask_enabled);
+#endif
+
+static DEFINE_SPINLOCK(sel_sem);
+
+/* global data for booleans */
+static int bool_num = 0;
+static int *bool_pending_values = NULL;
+
+extern int ss_initialized;
+
+extern struct xsm_operations *original_ops;
+
+static int domain_has_security(struct domain *d, u32 perms)
+{
+ struct domain_security_struct *dsec;
+
+ dsec = d->ssid;
+ if ( !dsec )
+ return -EACCES;
+
+ return avc_has_perm(dsec->sid, SECINITSID_SECURITY, SECCLASS_SECURITY,
+ perms, NULL);
+}
+
+static int flask_security_user(char *buf, int size)
+{
+ char *page = NULL;
+ char *con, *user, *ptr;
+ u32 sid, *sids;
+ int length;
+ char *newcon;
+ int i, rc;
+ u32 len, nsids;
+
+ length = domain_has_security(current->domain, SECURITY__COMPUTE_USER);
+ if ( length )
+ return length;
+
+ length = -ENOMEM;
+ con = xmalloc_array(char, size+1);
+ if ( !con )
+ return length;
+ memset(con, 0, size+1);
+
+ user = xmalloc_array(char, size+1);
+ if ( !user )
+ goto out;
+ memset(user, 0, size+1);
+
+ length = -ENOMEM;
+ page = xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ goto out2;
+ memset(page, 0, PAGE_SIZE);
+
+ length = -EFAULT;
+ if ( copy_from_user(page, buf, size) )
+ goto out2;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%s %s", con, user) != 2 )
+ goto out2;
+
+ length = security_context_to_sid(con, strlen(con)+1, &sid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_get_user_sids(sid, user, &sids, &nsids);
+ if ( length < 0 )
+ goto out2;
+
+ memset(page, 0, PAGE_SIZE);
+ length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
+ ptr = page + length;
+ for ( i = 0; i < nsids; i++ )
+ {
+ rc = security_sid_to_context(sids[i], &newcon, &len);
+ if ( rc )
+ {
+ length = rc;
+ goto out3;
+ }
+ if ( (length + len) >= PAGE_SIZE )
+ {
+ xfree(newcon);
+ length = -ERANGE;
+ goto out3;
+ }
+ memcpy(ptr, newcon, len);
+ xfree(newcon);
+ ptr += len;
+ length += len;
+ }
+
+ if ( copy_to_user(buf, page, length) )
+ length = -EFAULT;
+
+out3:
+ xfree(sids);
+out2:
+ if ( page )
+ xfree(page);
+ xfree(user);
+out:
+ xfree(con);
+ return length;
+}
+
+static int flask_security_relabel(char *buf, int size)
+{
+ char *scon, *tcon;
+ u32 ssid, tsid, newsid;
+ u16 tclass;
+ int length;
+ char *newcon;
+ u32 len;
+
+ length = domain_has_security(current->domain, SECURITY__COMPUTE_RELABEL);
+ if ( length )
+ return length;
+
+ length = -ENOMEM;
+ scon = xmalloc_array(char, size+1);
+ if ( !scon )
+ return length;
+ memset(scon, 0, size+1);
+
+ tcon = xmalloc_array(char, size+1);
+ if ( !tcon )
+ goto out;
+ memset(tcon, 0, size+1);
+
+ length = -EINVAL;
+ if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
+ goto out2;
+
+ length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+ if ( length < 0 )
+ goto out2;
+ length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_change_sid(ssid, tsid, tclass, &newsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_sid_to_context(newsid, &newcon, &len);
+ if ( length < 0 )
+ goto out2;
+
+ if ( len > PAGE_SIZE )
+ {
+ length = -ERANGE;
+ goto out3;
+ }
+
+ if ( copy_to_user(buf, newcon, len) )
+ len = -EFAULT;
+
+ length = len;
+
+out3:
+ xfree(newcon);
+out2:
+ xfree(tcon);
+out:
+ xfree(scon);
+ return length;
+}
+
+static int flask_security_create(char *buf, int size)
+{
+ char *scon, *tcon;
+ u32 ssid, tsid, newsid;
+ u16 tclass;
+ int length;
+ char *newcon;
+ u32 len;
+
+ length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
+ if ( length )
+ return length;
+
+ length = -ENOMEM;
+ scon = xmalloc_array(char, size+1);
+ if ( !scon )
+ return length;
+ memset(scon, 0, size+1);
+
+ tcon = xmalloc_array(char, size+1);
+ if ( !tcon )
+ goto out;
+ memset(tcon, 0, size+1);
+
+ length = -EINVAL;
+ if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
+ goto out2;
+
+ length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_transition_sid(ssid, tsid, tclass, &newsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_sid_to_context(newsid, &newcon, &len);
+ if ( length < 0 )
+ goto out2;
+
+ if ( len > PAGE_SIZE )
+ {
+ printk( "%s: context size (%u) exceeds payload "
+ "max\n", __FUNCTION__, len);
+ length = -ERANGE;
+ goto out3;
+ }
+
+ if ( copy_to_user(buf, newcon, len) )
+ len = -EFAULT;
+
+ length = len;
+
+out3:
+ xfree(newcon);
+out2:
+ xfree(tcon);
+out:
+ xfree(scon);
+ return length;
+}
+
+static int flask_security_access(char *buf, int size)
+{
+ char *page = NULL;
+ char *scon, *tcon;
+ u32 ssid, tsid;
+ u16 tclass;
+ u32 req;
+ struct av_decision avd;
+ int length;
+
+ length = domain_has_security(current->domain, SECURITY__COMPUTE_AV);
+ if ( length )
+ return length;
+
+ length = -ENOMEM;
+ scon = xmalloc_array(char, size+1);
+ if (!scon)
+ return length;
+ memset(scon, 0, size+1);
+
+ tcon = xmalloc_array(char, size+1);
+ if ( !tcon )
+ goto out;
+ memset( tcon, 0, size+1 );
+
+ length = -EINVAL;
+ if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4)
+ goto out2;
+
+ length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_compute_av(ssid, tsid, tclass, req, &avd);
+ if ( length < 0 )
+ goto out2;
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ {
+ length = -ENOMEM;
+ goto out2;
+ }
+
+ memset(page, 0, PAGE_SIZE);
+
+ length = snprintf(page, PAGE_SIZE, "%x %x %x %x %u",
+ avd.allowed, avd.decided,
+ avd.auditallow, avd.auditdeny,
+ avd.seqno);
+
+ if ( copy_to_user(buf, page, length) )
+ length = -EFAULT;
+
+out2:
+ xfree(tcon);
+out:
+ xfree(scon);
+ return length;
+}
+
+static int flask_security_member(char *buf, int size)
+{
+ char *scon, *tcon;
+ u32 ssid, tsid, newsid;
+ u16 tclass;
+ int length;
+ char *newcon;
+ u32 len;
+
+ length = domain_has_security(current->domain, SECURITY__COMPUTE_MEMBER);
+ if ( length )
+ return length;
+
+ length = -ENOMEM;
+ scon = xmalloc_array(char, size+1);
+ if ( !scon )
+ return length;
+ memset(scon, 0, size+1);
+
+ tcon = xmalloc_array(char, size+1);
+ if ( !tcon )
+ goto out;
+ memset(tcon, 0, size+1);
+
+ length = -EINVAL;
+ if ( sscanf(buf, "%s, %s, %hu", scon, tcon, &tclass) != 3 )
+ goto out2;
+
+ length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_member_sid(ssid, tsid, tclass, &newsid);
+ if ( length < 0 )
+ goto out2;
+
+ length = security_sid_to_context(newsid, &newcon, &len);
+ if ( length < 0 )
+ goto out2;
+
+ if ( len > PAGE_SIZE )
+ {
+ printk("%s: context size (%u) exceeds payload "
+ "max\n", __FUNCTION__, len);
+ length = -ERANGE;
+ goto out3;
+ }
+
+ if ( copy_to_user(buf, newcon, len) )
+ len = -EFAULT;
+
+ length = len;
+
+out3:
+ xfree(newcon);
+out2:
+ xfree(tcon);
+out:
+ xfree(scon);
+ return length;
+}
+
+static int flask_security_setenforce(char *buf, int count)
+{
+ char *page = NULL;
+ int length;
+ int new_value;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ return -ENOMEM;
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+ length = -EFAULT;
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%d", &new_value) != 1 )
+ goto out;
+
+ if ( new_value != flask_enforcing )
+ {
+ length = domain_has_security(current->domain, SECURITY__SETENFORCE);
+ if ( length )
+ goto out;
+ flask_enforcing = new_value;
+ if ( flask_enforcing )
+ avc_ss_reset(0);
+ }
+ length = count;
+
+out:
+ xfree(page);
+ return length;
+}
+
+static int flask_security_context(char *buf, int count)
+{
+ char *page = NULL;
+ u32 sid;
+ int length;
+
+ length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+ if ( length )
+ goto out;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ return -ENOMEM;
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+ length = -EFAULT;
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = security_context_to_sid(page, count, &sid);
+ if ( length < 0 )
+ goto out;
+
+ memset(page, 0, PAGE_SIZE);
+ length = snprintf(page, PAGE_SIZE, "%u", sid);
+
+ if ( copy_to_user(buf, page, count) )
+ length = -EFAULT;
+
+out:
+ xfree(page);
+ return length;
+}
+
+static int flask_security_sid(char *buf, int count)
+{
+ char *page = NULL;
+ char *context;
+ u32 sid;
+ u32 len;
+ int length;
+
+ length = domain_has_security(current->domain, SECURITY__CHECK_CONTEXT);
+ if ( length )
+ goto out;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ return -ENOMEM;
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+ length = -EFAULT;
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ if ( sscanf(page, "%u", &sid) != 1 )
+ goto out;
+
+ length = security_sid_to_context(sid, &context, &len);
+ if ( length < 0 )
+ goto out;
+
+ if ( copy_to_user(buf, context, len) )
+ length = -EFAULT;
+
+ xfree(context);
+
+out:
+ xfree(page);
+ return length;
+}
+
+int flask_disable(void)
+{
+ static int flask_disabled = 0;
+
+ if ( ss_initialized )
+ {
+ /* Not permitted after initial policy load. */
+ return -EINVAL;
+ }
+
+ if ( flask_disabled )
+ {
+ /* Only do this once. */
+ return -EINVAL;
+ }
+
+ printk("Flask: Disabled at runtime.\n");
+
+ flask_disabled = 1;
+
+ /* Reset xsm_ops to the original module. */
+ xsm_ops = original_ops;
+
+ return 0;
+}
+
+static int flask_security_disable(char *buf, int count)
+{
+ char *page = NULL;
+ int length;
+ int new_value;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ return -ENOMEM;
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+ length = -EFAULT;
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%d", &new_value) != 1 )
+ goto out;
+
+ if ( new_value )
+ {
+ length = flask_disable();
+ if ( length < 0 )
+ goto out;
+ }
+
+ length = count;
+
+out:
+ xfree(page);
+ return length;
+}
+
+static int flask_security_setavc_threshold(char *buf, int count)
+{
+ char *page = NULL;
+ int ret;
+ int new_value;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ page = (char*)xmalloc_bytes(PAGE_SIZE);
+ if (!page)
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ if ( copy_from_user(page, buf, count) )
+ {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ if ( sscanf(page, "%u", &new_value) != 1 )
+ {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ if ( new_value != avc_cache_threshold )
+ {
+ ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
+ if ( ret )
+ goto out_free;
+ avc_cache_threshold = new_value;
+ }
+ ret = count;
+
+out_free:
+ xfree(page);
+out:
+ return ret;
+}
+
+static int flask_security_set_bool(char *buf, int count)
+{
+ char *page = NULL;
+ int length = -EFAULT;
+ int i, new_value;
+
+ spin_lock(&sel_sem);
+
+ length = domain_has_security(current->domain, SECURITY__SETBOOL);
+ if ( length )
+ goto out;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+ memset(page, 0, PAGE_SIZE);
+
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%d %d", &i, &new_value) != 2 )
+ goto out;
+
+ if ( new_value )
+ {
+ new_value = 1;
+ }
+
+ bool_pending_values[i] = new_value;
+ length = count;
+
+out:
+ spin_unlock(&sel_sem);
+ if ( page )
+ xfree(page);
+ return length;
+}
+
+static int flask_security_commit_bools(char *buf, int count)
+{
+ char *page = NULL;
+ int length = -EFAULT;
+ int new_value;
+
+ spin_lock(&sel_sem);
+
+ length = domain_has_security(current->domain, SECURITY__SETBOOL);
+ if ( length )
+ goto out;
+
+ if ( count < 0 || count >= PAGE_SIZE )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+ memset(page, 0, PAGE_SIZE);
+
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%d", &new_value) != 1 )
+ goto out;
+
+ if ( new_value )
+ security_set_bools(bool_num, bool_pending_values);
+
+ length = count;
+
+out:
+ spin_unlock(&sel_sem);
+ if ( page )
+ xfree(page);
+ return length;
+}
+
+static int flask_security_get_bool(char *buf, int count)
+{
+ char *page = NULL;
+ int length;
+ int i, cur_enforcing;
+
+ spin_lock(&sel_sem);
+
+ length = -EFAULT;
+
+ if ( count < 0 || count > PAGE_SIZE )
+ {
+ length = -EINVAL;
+ goto out;
+ }
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+ memset(page, 0, PAGE_SIZE);
+
+ if ( copy_from_user(page, buf, count) )
+ goto out;
+
+ length = -EINVAL;
+ if ( sscanf(page, "%d", &i) != 1 )
+ goto out;
+
+ cur_enforcing = security_get_bool_value(i);
+ if ( cur_enforcing < 0 )
+ {
+ length = cur_enforcing;
+ goto out;
+ }
+
+ length = snprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
+ bool_pending_values[i]);
+ if ( length < 0 )
+ goto out;
+
+ if ( copy_to_user(buf, page, length) )
+ length = -EFAULT;
+
+out:
+ spin_unlock(&sel_sem);
+ if ( page )
+ xfree(page);
+ return length;
+}
+
+static int flask_security_make_bools(void)
+{
+ int i, ret = 0;
+ char **names = NULL;
+ int num;
+ int *values = NULL;
+
+ xfree(bool_pending_values);
+
+ ret = security_get_bools(&num, &names, &values);
+ if ( ret != 0 )
+ goto out;
+
+ bool_num = num;
+ bool_pending_values = values;
+
+out:
+ if ( names )
+ {
+ for ( i = 0; i < num; i++ )
+ xfree(names[i]);
+ xfree(names);
+ }
+ return ret;
+}
+
+#ifdef FLASK_AVC_STATS
+
+static int flask_security_avc_cachestats(char *buf, int count)
+{
+ char *page = NULL;
+ int len = 0;
+ int length = 0;
+ long long idx = 0;
+ int cpu;
+ struct avc_cache_stats *st;
+
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
+ "frees\n");
+ memcpy(buf, page, len);
+ buf += len;
+ length += len;
+
+ for ( cpu = idx; cpu < NR_CPUS; ++cpu )
+ {
+ if ( !cpu_possible(cpu) )
+ continue;
+ idx = cpu + 1;
+ st = &per_cpu(avc_cache_stats, cpu);
+
+ len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
+ st->hits, st->misses, st->allocations,
+ st->reclaims, st->frees);
+ memcpy(buf, page, len);
+ buf += len;
+ length += len;
+ }
+
+ xfree(page);
+ return length;
+}
+
+#endif
+
+static int flask_security_load(char *buf, int count)
+{
+ int ret;
+ int length;
+ void *data = NULL;
+
+ spin_lock(&sel_sem);
+
+ length = domain_has_security(current->domain, SECURITY__LOAD_POLICY);
+ if ( length )
+ goto out;
+
+ if ( (count < 0) || (count > 64 * 1024 * 1024)
+ || (data = xmalloc_array(char, count)) == NULL )
+ {
+ length = -ENOMEM;
+ goto out;
+ }
+
+ length = -EFAULT;
+ if ( copy_from_user(data, buf, count) != 0 )
+ goto out;
+
+ length = security_load_policy(data, count);
+ if ( length )
+ goto out;
+
+ ret = flask_security_make_bools();
+ if ( ret )
+ length = ret;
+ else
+ length = count;
+
+out:
+ spin_unlock(&sel_sem);
+ xfree(data);
+ return length;
+}
+
+long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
+{
+ flask_op_t curop, *op = &curop;
+ int rc = 0;
+ int length = 0;
+ char *page = NULL;
+
+ if ( copy_from_guest(op, u_flask_op, 1) )
+ return -EFAULT;
+
+ switch ( op->cmd )
+ {
+
+ case FLASK_LOAD:
+ {
+ length = flask_security_load(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_GETENFORCE:
+ {
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ length = snprintf(page, PAGE_SIZE, "%d", flask_enforcing);
+
+ if ( copy_to_user(op->buf, page, length) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+ }
+ break;
+
+ case FLASK_SETENFORCE:
+ {
+ length = flask_security_setenforce(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_CONTEXT_TO_SID:
+ {
+ length = flask_security_context(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_SID_TO_CONTEXT:
+ {
+ length = flask_security_sid(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_ACCESS:
+ {
+ length = flask_security_access(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_CREATE:
+ {
+ length = flask_security_create(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_RELABEL:
+ {
+ length = flask_security_relabel(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_USER:
+ {
+ length = flask_security_user(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_POLICYVERS:
+ {
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ length = snprintf(page, PAGE_SIZE, "%d", POLICYDB_VERSION_MAX);
+
+ if ( copy_to_user(op->buf, page, length) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+ }
+ break;
+
+ case FLASK_GETBOOL:
+ {
+ length = flask_security_get_bool(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_SETBOOL:
+ {
+ length = flask_security_set_bool(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_COMMITBOOLS:
+ {
+ length = flask_security_commit_bools(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_MLS:
+ {
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ length = snprintf(page, PAGE_SIZE, "%d", flask_mls_enabled);
+
+ if ( copy_to_user(op->buf, page, length) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+ }
+ break;
+
+ case FLASK_DISABLE:
+ {
+ length = flask_security_disable(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_GETAVC_THRESHOLD:
+ {
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ length = snprintf(page, PAGE_SIZE, "%d", avc_cache_threshold);
+
+ if ( copy_to_user(op->buf, page, length) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+ }
+ break;
+
+ case FLASK_SETAVC_THRESHOLD:
+ {
+ length = flask_security_setavc_threshold(op->buf, op->size);
+ }
+ break;
+
+ case FLASK_AVC_HASHSTATS:
+ {
+ page = (char *)xmalloc_bytes(PAGE_SIZE);
+ if ( !page )
+ return -ENOMEM;
+ memset(page, 0, PAGE_SIZE);
+
+ length = avc_get_hash_stats(page);
+
+ if ( copy_to_user(op->buf, page, length) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+ }
+ break;
+
+#ifdef FLASK_AVC_STATS
+ case FLASK_AVC_CACHESTATS:
+ {
+ length = flask_security_avc_cachestats(op->buf, op->size);
+ }
+ break;
+#endif
+
+ case FLASK_MEMBER:
+ {
+ length = flask_security_member(op->buf, op->size);
+ }
+ break;
+
+ default:
+ length = -ENOSYS;
+ break;
+
+ }
+
+ if ( length < 0 )
+ {
+ rc = length;
+ goto out;
+ }
+ op->size = length;
+ if ( copy_to_guest(u_flask_op, op, 1) )
+ rc = -EFAULT;
+
+out:
+ if ( page )
+ xfree(page);
+ return rc;
+}
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/hooks.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/hooks.c Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1159 @@
+ /*
+ * This file contains the Flask hook function implementations for Xen.
+ *
+ * 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.
+ */
+
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/xmalloc.h>
+#include <xsm/xsm.h>
+#include <xen/spinlock.h>
+#include <xen/cpumask.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <public/xen.h>
+#include <public/physdev.h>
+#include <public/platform.h>
+
+#include <public/xsm/flask_op.h>
+
+#include <avc.h>
+#include <avc_ss.h>
+#include <objsec.h>
+#include <conditional.h>
+
+struct xsm_operations *original_ops = NULL;
+
+static int domain_has_perm(struct domain *dom1, struct domain *dom2,
+ u16 class, u32 perms)
+{
+ struct domain_security_struct *dsec1, *dsec2;
+
+ dsec1 = dom1->ssid;
+ dsec2 = dom2->ssid;
+
+ return avc_has_perm(dsec1->sid, dsec2->sid, class, perms, NULL);
+}
+
+static int domain_has_evtchn(struct domain *d, struct evtchn *chn, u32 perms)
+{
+ struct domain_security_struct *dsec;
+ struct evtchn_security_struct *esec;
+
+ dsec = d->ssid;
+ esec = chn->ssid;
+
+ return avc_has_perm(dsec->sid, esec->sid, SECCLASS_EVENT, perms, NULL);
+}
+
+static int domain_has_xen(struct domain *d, u32 perms)
+{
+ struct domain_security_struct *dsec;
+ dsec = d->ssid;
+
+ return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN, perms, NULL);
+}
+
+static int flask_domain_alloc_security(struct domain *d)
+{
+ struct domain_security_struct *dsec;
+
+ dsec = xmalloc(struct domain_security_struct);
+
+ if ( !dsec )
+ return -ENOMEM;
+
+ memset(dsec, 0, sizeof(struct domain_security_struct));
+
+ dsec->d = d;
+
+ if ( d->domain_id == IDLE_DOMAIN_ID )
+ {
+ dsec->sid = SECINITSID_XEN;
+ dsec->create_sid = SECINITSID_DOM0;
+ }
+ else
+ {
+ dsec->sid = SECINITSID_UNLABELED;
+ dsec->create_sid = SECSID_NULL;
+ }
+
+ d->ssid = dsec;
+
+ return 0;
+}
+
+static void flask_domain_free_security(struct domain *d)
+{
+ struct domain_security_struct *dsec = d->ssid;
+
+ if ( !dsec )
+ return;
+
+ d->ssid = NULL;
+ xfree(dsec);
+}
+
+static int flask_evtchn_unbound(struct domain *d1, struct evtchn *chn,
+ domid_t id2)
+{
+ u32 newsid;
+ int rc;
+ domid_t id;
+ struct domain *d2;
+ struct domain_security_struct *dsec, *dsec1, *dsec2;
+ struct evtchn_security_struct *esec;
+
+ dsec = current->domain->ssid;
+ dsec1 = d1->ssid;
+ esec = chn->ssid;
+
+ if ( id2 == DOMID_SELF )
+ id = current->domain->domain_id;
+ else
+ id = id2;
+
+ d2 = get_domain_by_id(id);
+ if ( d2 == NULL )
+ return -EPERM;
+
+ dsec2 = d2->ssid;
+ rc = security_transition_sid(dsec1->sid, dsec2->sid, SECCLASS_EVENT,
+ &newsid);
+ if ( rc )
+ goto out;
+
+ rc = avc_has_perm(dsec->sid, newsid, SECCLASS_EVENT,
+ EVENT__CREATE|EVENT__ALLOC, NULL);
+ if ( rc )
+ goto out;
+
+ rc = avc_has_perm(newsid, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+ if ( rc )
+ goto out;
+ else
+ esec->sid = newsid;
+
+out:
+ put_domain(d2);
+ return rc;
+}
+
+static int flask_evtchn_interdomain(struct domain *d1, struct evtchn *chn1,
+ struct domain *d2, struct evtchn *chn2)
+{
+ u32 newsid1;
+ u32 newsid2;
+ int rc;
+ struct domain_security_struct *dsec1, *dsec2;
+ struct evtchn_security_struct *esec1, *esec2;
+
+ dsec1 = d1->ssid;
+ dsec2 = d2->ssid;
+
+ esec1 = chn1->ssid;
+ esec2 = chn2->ssid;
+
+ rc = security_transition_sid(dsec1->sid, dsec2->sid,
+ SECCLASS_EVENT, &newsid1);
+ if ( rc )
+ {
+ printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+ __FUNCTION__, -rc, d2->domain_id);
+ return rc;
+ }
+
+ rc = avc_has_perm(dsec1->sid, newsid1, SECCLASS_EVENT, EVENT__CREATE, NULL);
+ if ( rc )
+ return rc;
+
+ rc = security_transition_sid(dsec2->sid, dsec1->sid,
+ SECCLASS_EVENT, &newsid2);
+ if ( rc )
+ {
+ printk("%s: security_transition_sid failed, rc=%d (domain=%d)\n",
+ __FUNCTION__, -rc, d1->domain_id);
+ return rc;
+ }
+
+ rc = avc_has_perm(dsec2->sid, newsid2, SECCLASS_EVENT, EVENT__CREATE, NULL);
+ if ( rc )
+ return rc;
+
+ rc = avc_has_perm(newsid1, dsec2->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+ if ( rc )
+ return rc;
+
+ rc = avc_has_perm(newsid2, dsec1->sid, SECCLASS_EVENT, EVENT__BIND, NULL);
+ if ( rc )
+ return rc;
+
+ esec1->sid = newsid1;
+ esec2->sid = newsid2;
+
+ return rc;
+}
+
+static void flask_evtchn_close_post(struct evtchn *chn)
+{
+ struct evtchn_security_struct *esec;
+ esec = chn->ssid;
+
+ esec->sid = SECINITSID_UNLABELED;
+}
+
+static int flask_evtchn_send(struct domain *d, struct evtchn *chn)
+{
+ return domain_has_evtchn(d, chn, EVENT__SEND);
+}
+
+static int flask_evtchn_status(struct domain *d, struct evtchn *chn)
+{
+ return domain_has_evtchn(d, chn, EVENT__STATUS);
+}
+
+static int flask_evtchn_reset(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_EVENT, EVENT__RESET);
+}
+
+static int flask_alloc_security_evtchn(struct evtchn *chn)
+{
+ struct evtchn_security_struct *esec;
+
+ esec = xmalloc(struct evtchn_security_struct);
+
+ if ( !esec )
+ return -ENOMEM;
+
+ memset(esec, 0, sizeof(struct evtchn_security_struct));
+
+ esec->chn = chn;
+ esec->sid = SECINITSID_UNLABELED;
+
+ chn->ssid = esec;
+
+ return 0;
+}
+
+static void flask_free_security_evtchn(struct evtchn *chn)
+{
+ struct evtchn_security_struct *esec;
+
+ if ( !chn )
+ return;
+
+ esec = chn->ssid;
+
+ if ( !esec )
+ return;
+
+ chn->ssid = NULL;
+ xfree(esec);
+}
+
+static int flask_grant_mapref(struct domain *d1, struct domain *d2,
+ uint32_t flags)
+{
+ u32 perms = GRANT__MAP_READ;
+
+ if ( flags & GTF_writing )
+ perms |= GRANT__MAP_WRITE;
+
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, perms);
+}
+
+static int flask_grant_unmapref(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__UNMAP);
+}
+
+static int flask_grant_setup(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__SETUP);
+}
+
+static int flask_grant_transfer(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__TRANSFER);
+}
+
+static int flask_grant_copy(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__COPY);
+}
+
+static int flask_grant_query_size(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_GRANT, GRANT__QUERY);
+}
+
+static int get_page_sid(struct page_info *page, u32 *sid)
+{
+ int rc = 0;
+ struct domain *d;
+ struct domain_security_struct *dsec;
+ unsigned long mfn;
+
+ d = page_get_owner(page);
+
+ if ( d == NULL )
+ {
+ mfn = page_to_mfn(page);
+ rc = security_iomem_sid(mfn, sid);
+ return rc;
+ }
+
+ switch ( d->domain_id )
+ {
+ case DOMID_IO:
+ /*A tracked IO page?*/
+ *sid = SECINITSID_DOMIO;
+ break;
+
+ case DOMID_XEN:
+ /*A page from Xen's private heap?*/
+ *sid = SECINITSID_DOMXEN;
+ break;
+
+ default:
+ /*Pages are implicitly labeled by domain ownership!*/
+ dsec = d->ssid;
+ *sid = dsec->sid;
+ break;
+ }
+
+ return rc;
+}
+
+static int get_mfn_sid(unsigned long mfn, u32 *sid)
+{
+ int rc = 0;
+ struct page_info *page;
+
+ if ( mfn_valid(mfn) )
+ {
+ /*mfn is valid if this is a page that Xen is tracking!*/
+ page = mfn_to_page(mfn);
+ rc = get_page_sid(page, sid);
+ }
+ else
+ {
+ /*Possibly an untracked IO page?*/
+ rc = security_iomem_sid(mfn, sid);
+ }
+
+ return rc;
+}
+
+static int flask_translate_gpfn_list(struct domain *d, unsigned long mfn)
+{
+ int rc = 0;
+ u32 sid;
+ struct domain_security_struct *dsec;
+ dsec = d->ssid;
+
+ rc = get_mfn_sid(mfn, &sid);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__TRANSLATEGP, NULL);
+}
+
+static int flask_memory_adjust_reservation(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__ADJUST);
+}
+
+static int flask_memory_stat_reservation(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__STAT);
+}
+
+static int flask_memory_pin_page(struct domain *d, struct page_info *page)
+{
+ int rc = 0;
+ u32 sid;
+ struct domain_security_struct *dsec;
+ dsec = d->ssid;
+
+ rc = get_page_sid(page, &sid);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(dsec->sid, sid, SECCLASS_MMU, MMU__PINPAGE, NULL);
+}
+
+/* Used to defer flushing of memory structures. */
+struct percpu_mm_info {
+#define DOP_FLUSH_TLB (1<<0) /* Flush the local TLB. */
+#define DOP_FLUSH_ALL_TLBS (1<<1) /* Flush TLBs of all VCPUs of current dom. */
+#define DOP_RELOAD_LDT (1<<2) /* Reload the LDT shadow mapping. */
+ unsigned int deferred_ops;
+ /* If non-NULL, specifies a foreign subject domain for some operations. */
+ struct domain *foreign;
+};
+static DEFINE_PER_CPU(struct percpu_mm_info, percpu_mm_info);
+
+/*
+ * Returns the current foreign domain; defaults to the currently-executing
+ * domain if a foreign override hasn't been specified.
+ */
+#define FOREIGNDOM (this_cpu(percpu_mm_info).foreign ?: current->domain)
+
+static int flask_update_va_mapping(struct domain *d, l1_pgentry_t pte)
+{
+ int rc = 0;
+ u32 psid;
+ u32 map_perms = MMU__MAP_READ;
+ unsigned long mfn;
+ struct domain_security_struct *dsec;
+
+ dsec = d->ssid;
+
+ mfn = gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(pte));
+ rc = get_mfn_sid(mfn, &psid);
+ if ( rc )
+ return rc;
+
+ if ( l1e_get_flags(pte) & _PAGE_RW )
+ map_perms |= MMU__MAP_WRITE;
+
+ return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_console_io(struct domain *d, int cmd)
+{
+ u32 perm;
+
+ switch ( cmd )
+ {
+ case CONSOLEIO_read:
+ perm = XEN__READCONSOLE;
+ break;
+ case CONSOLEIO_write:
+ perm = XEN__WRITECONSOLE;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_xen(d, perm);
+}
+
+static int flask_profile(struct domain *d, int op)
+{
+ u32 perm;
+
+ switch ( op )
+ {
+ case XENOPROF_init:
+ case XENOPROF_enable_virq:
+ case XENOPROF_disable_virq:
+ case XENOPROF_get_buffer:
+ perm = XEN__NONPRIVPROFILE;
+ break;
+ case XENOPROF_reset_active_list:
+ case XENOPROF_reset_passive_list:
+ case XENOPROF_set_active:
+ case XENOPROF_set_passive:
+ case XENOPROF_reserve_counters:
+ case XENOPROF_counter:
+ case XENOPROF_setup_events:
+ case XENOPROF_start:
+ case XENOPROF_stop:
+ case XENOPROF_release_counters:
+ case XENOPROF_shutdown:
+ perm = XEN__PRIVPROFILE;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_xen(d, perm);
+}
+
+static int flask_kexec(void)
+{
+ return domain_has_xen(current->domain, XEN__KEXEC);
+}
+
+static int flask_schedop_shutdown(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_DOMAIN, DOMAIN__SHUTDOWN);
+}
+
+static void flask_security_domaininfo(struct domain *d,
+ struct xen_domctl_getdomaininfo *info)
+{
+ struct domain_security_struct *dsec;
+
+ dsec = d->ssid;
+ info->ssidref = dsec->sid;
+}
+
+static int flask_setvcpucontext(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__SETVCPUCONTEXT);
+}
+
+static int flask_pausedomain(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__PAUSE);
+}
+
+static int flask_unpausedomain(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__UNPAUSE);
+}
+
+static int flask_resumedomain(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__RESUME);
+}
+
+static int flask_domain_create(struct domain *d, u32 ssidref)
+{
+ int rc;
+ struct domain_security_struct *dsec1;
+ struct domain_security_struct *dsec2;
+
+ dsec1 = current->domain->ssid;
+
+ if ( dsec1->create_sid == SECSID_NULL )
+ dsec1->create_sid = ssidref;
+
+ rc = avc_has_perm(dsec1->sid, dsec1->create_sid, SECCLASS_DOMAIN,
+ DOMAIN__CREATE, NULL);
+ if ( rc )
+ {
+ dsec1->create_sid = SECSID_NULL;
+ return rc;
+ }
+
+ dsec2 = d->ssid;
+ dsec2->sid = dsec1->create_sid;
+
+ dsec1->create_sid = SECSID_NULL;
+ dsec2->create_sid = SECSID_NULL;
+
+ return rc;
+}
+
+static int flask_max_vcpus(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__MAX_VCPUS);
+}
+
+static int flask_destroydomain(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__DESTROY);
+}
+
+static int flask_vcpuaffinity(int cmd, struct domain *d)
+{
+ u32 perm;
+
+ switch ( cmd )
+ {
+ case XEN_DOMCTL_setvcpuaffinity:
+ perm = DOMAIN__SETVCPUAFFINITY;
+ break;
+ case XEN_DOMCTL_getvcpuaffinity:
+ perm = DOMAIN__GETVCPUAFFINITY;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm );
+}
+
+static int flask_scheduler(struct domain *d)
+{
+ int rc = 0;
+
+ rc = domain_has_xen(current->domain, XEN__SCHEDULER);
+ if ( rc )
+ return rc;
+
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__SCHEDULER);
+}
+
+static int flask_getdomaininfo(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__GETDOMAININFO);
+}
+
+static int flask_getvcpucontext(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__GETVCPUCONTEXT);
+}
+
+static int flask_getvcpuinfo(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__GETVCPUINFO);
+}
+
+static int flask_domain_settime(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, DOMAIN__SETTIME);
+}
+
+static int flask_tbufcontrol(void)
+{
+ return domain_has_xen(current->domain, SECCLASS_XEN);
+}
+
+static int flask_readconsole(uint32_t clear)
+{
+ u32 perms = XEN__READCONSOLE;
+
+ if ( clear )
+ perms |= XEN__CLEARCONSOLE;
+
+ return domain_has_xen(current->domain, perms);
+}
+
+static int flask_sched_id(void)
+{
+ return domain_has_xen(current->domain, XEN__SCHEDULER);
+}
+
+static int flask_setdomainmaxmem(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__SETDOMAINMAXMEM);
+}
+
+static int flask_setdomainhandle(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__SETDOMAINHANDLE);
+}
+
+static int flask_setdebugging(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__SETDEBUGGING);
+}
+
+static inline u32 resource_to_perm(uint8_t access)
+{
+ if ( access )
+ return RESOURCE__ADD;
+ else
+ return RESOURCE__REMOVE;
+}
+
+static int flask_irq_permission(struct domain *d, uint8_t pirq, uint8_t access)
+{
+ u32 perm;
+ u32 rsid;
+ int rc = -EPERM;
+
+ struct domain_security_struct *ssec, *tsec;
+
+ rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+ resource_to_perm(access));
+
+ if ( rc )
+ return rc;
+
+ if ( access )
+ perm = RESOURCE__ADD_IRQ;
+ else
+ perm = RESOURCE__REMOVE_IRQ;
+
+ ssec = current->domain->ssid;
+ tsec = d->ssid;
+
+ rc = security_pirq_sid(pirq, &rsid);
+ if ( rc )
+ return rc;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
+ RESOURCE__USE, NULL);
+}
+
+static int flask_iomem_permission(struct domain *d, unsigned long mfn,
+ uint8_t access)
+{
+ u32 perm;
+ u32 rsid;
+ int rc = -EPERM;
+
+ struct domain_security_struct *ssec, *tsec;
+
+ rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+ resource_to_perm(access));
+
+ if ( rc )
+ return rc;
+
+ if ( access )
+ perm = RESOURCE__ADD_IOMEM;
+ else
+ perm = RESOURCE__REMOVE_IOMEM;
+
+ ssec = current->domain->ssid;
+ tsec = d->ssid;
+
+ rc = security_iomem_sid(mfn, &rsid);
+ if ( rc )
+ return rc;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
+ RESOURCE__USE, NULL);
+}
+
+static int flask_perfcontrol(void)
+{
+ return domain_has_xen(current->domain, XEN__PERFCONTROL);
+}
+
+void flask_complete_init(struct domain *d)
+{
+ struct domain_security_struct *dsec;
+
+ /* Set the security state for the Dom0 domain. */
+ dsec = d->ssid;
+ dsec->sid = SECINITSID_DOM0;
+ dsec->create_sid = SECINITSID_UNLABELED;
+
+ printk("Flask: Completed initialization.\n");
+}
+
+#ifdef CONFIG_X86
+static int flask_shadow_control(struct domain *d, uint32_t op)
+{
+ u32 perm;
+
+ switch ( op )
+ {
+ case XEN_DOMCTL_SHADOW_OP_OFF:
+ perm = SHADOW__DISABLE;
+ break;
+ case XEN_DOMCTL_SHADOW_OP_ENABLE:
+ case XEN_DOMCTL_SHADOW_OP_ENABLE_TEST:
+ case XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE:
+ case XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION:
+ case XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION:
+ perm = SHADOW__ENABLE;
+ break;
+ case XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY:
+ case XEN_DOMCTL_SHADOW_OP_PEEK:
+ case XEN_DOMCTL_SHADOW_OP_CLEAN:
+ perm = SHADOW__LOGDIRTY;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_perm(current->domain, d, SECCLASS_SHADOW, perm);
+}
+
+static int flask_ioport_permission(struct domain *d, uint32_t ioport,
+ uint8_t access)
+{
+ u32 perm;
+ u32 rsid;
+ int rc = -EPERM;
+
+ struct domain_security_struct *ssec, *tsec;
+
+ rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
+ resource_to_perm(access));
+
+ if ( rc )
+ return rc;
+
+ if ( access )
+ perm = RESOURCE__ADD_IOPORT;
+ else
+ perm = RESOURCE__REMOVE_IOPORT;
+
+ ssec = current->domain->ssid;
+ tsec = d->ssid;
+
+ rc = security_ioport_sid(ioport, &rsid);
+ if ( rc )
+ return rc;
+
+ rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, NULL);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE,
+ RESOURCE__USE, NULL);
+}
+
+static int flask_getpageframeinfo(struct page_info *page)
+{
+ int rc = 0;
+ u32 tsid;
+ struct domain_security_struct *dsec;
+
+ dsec = current->domain->ssid;
+
+ rc = get_page_sid(page, &tsid);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(dsec->sid, tsid, SECCLASS_MMU, MMU__PAGEINFO, NULL);
+}
+
+static int flask_getmemlist(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__PAGELIST);
+}
+
+static int flask_hypercall_init(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN,
+ DOMAIN__HYPERCALL);
+}
+
+static int flask_hvmcontext(struct domain *d, uint32_t cmd)
+{
+ u32 perm;
+
+ switch ( cmd )
+ {
+ case XEN_DOMCTL_sethvmcontext:
+ perm = HVM__SETHVMC;
+ break;
+ case XEN_DOMCTL_gethvmcontext:
+ perm = HVM__GETHVMC;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_address_size(struct domain *d, uint32_t cmd)
+{
+ u32 perm;
+
+ switch ( cmd )
+ {
+ case XEN_DOMCTL_set_address_size:
+ perm = DOMAIN__SETADDRSIZE;
+ break;
+ case XEN_DOMCTL_get_address_size:
+ perm = DOMAIN__GETADDRSIZE;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm);
+}
+
+static int flask_hvm_param(struct domain *d, unsigned long op)
+{
+ u32 perm;
+
+ switch ( op )
+ {
+ case HVMOP_set_param:
+ perm = HVM__SETPARAM;
+ break;
+ case HVMOP_get_param:
+ perm = HVM__GETPARAM;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_perm(current->domain, d, SECCLASS_HVM, perm);
+}
+
+static int flask_hvm_set_pci_intx_level(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCILEVEL);
+}
+
+static int flask_hvm_set_isa_irq_level(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__IRQLEVEL);
+}
+
+static int flask_hvm_set_pci_link_route(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_HVM, HVM__PCIROUTE);
+}
+
+static int flask_apic(struct domain *d, int cmd)
+{
+ u32 perm;
+
+ switch ( cmd )
+ {
+ case PHYSDEVOP_APIC_READ:
+ perm = XEN__READAPIC;
+ break;
+ case PHYSDEVOP_APIC_WRITE:
+ perm = XEN__WRITEAPIC;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_xen(d, perm);
+}
+
+static int flask_assign_vector(struct domain *d, uint32_t pirq)
+{
+ u32 psid;
+ struct domain_security_struct *dsec;
+ dsec = d->ssid;
+
+ if ( security_pirq_sid(pirq, &psid) )
+ return -EPERM;
+
+ return avc_has_perm(dsec->sid, psid, SECCLASS_EVENT, EVENT__VECTOR, NULL);
+}
+
+static int flask_xen_settime(void)
+{
+ return domain_has_xen(current->domain, XEN__SETTIME);
+}
+
+static int flask_memtype(uint32_t access)
+{
+ u32 perm;
+
+ switch ( access )
+ {
+ case XENPF_add_memtype:
+ perm = XEN__MTRR_ADD;
+ break;
+ case XENPF_del_memtype:
+ perm = XEN__MTRR_DEL;
+ break;
+ case XENPF_read_memtype:
+ perm = XEN__MTRR_READ;
+ break;
+ default:
+ return -EPERM;
+ }
+
+ return domain_has_xen(current->domain, perm);
+}
+
+static int flask_microcode(void)
+{
+ return domain_has_xen(current->domain, XEN__MICROCODE);
+}
+
+static int flask_physinfo(void)
+{
+ return domain_has_xen(current->domain, XEN__PHYSINFO);
+}
+
+static int flask_platform_quirk(uint32_t quirk)
+{
+ struct domain_security_struct *dsec;
+ dsec = current->domain->ssid;
+
+ return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_XEN,
+ XEN__QUIRK, NULL);
+}
+
+static int flask_machine_memory_map(void)
+{
+ struct domain_security_struct *dsec;
+ dsec = current->domain->ssid;
+
+ return avc_has_perm(dsec->sid, SECINITSID_XEN, SECCLASS_MMU,
+ MMU__MEMORYMAP, NULL);
+}
+
+static int flask_domain_memory_map(struct domain *d)
+{
+ return domain_has_perm(current->domain, d, SECCLASS_MMU, MMU__MEMORYMAP);
+}
+
+static int flask_mmu_normal_update(struct domain *d, intpte_t fpte)
+{
+ int rc = 0;
+ u32 map_perms = MMU__MAP_READ;
+ unsigned long fmfn;
+ struct domain_security_struct *dsec;
+ u32 fsid;
+
+ dsec = d->ssid;
+
+ if ( l1e_get_flags(l1e_from_intpte(fpte)) & _PAGE_RW )
+ map_perms |= MMU__MAP_WRITE;
+
+ fmfn = gmfn_to_mfn(FOREIGNDOM, l1e_get_pfn(l1e_from_intpte(fpte)));
+
+ rc = get_mfn_sid(fmfn, &fsid);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(dsec->sid, fsid, SECCLASS_MMU, map_perms, NULL);
+}
+
+static int flask_mmu_machphys_update(struct domain *d, unsigned long mfn)
+{
+ int rc = 0;
+ u32 psid;
+ struct domain_security_struct *dsec;
+ dsec = d->ssid;
+
+ rc = get_mfn_sid(mfn, &psid);
+ if ( rc )
+ return rc;
+
+ return avc_has_perm(dsec->sid, psid, SECCLASS_MMU, MMU__UPDATEMP, NULL);
+}
+
+static int flask_add_to_physmap(struct domain *d1, struct domain *d2)
+{
+ return domain_has_perm(d1, d2, SECCLASS_MMU, MMU__PHYSMAP);
+}
+#endif
+
+static struct xsm_operations flask_ops = {
+ .security_domaininfo = flask_security_domaininfo,
+ .setvcpucontext = flask_setvcpucontext,
+ .pausedomain = flask_pausedomain,
+ .unpausedomain = flask_unpausedomain,
+ .resumedomain = flask_resumedomain,
+ .domain_create = flask_domain_create,
+ .max_vcpus = flask_max_vcpus,
+ .destroydomain = flask_destroydomain,
+ .vcpuaffinity = flask_vcpuaffinity,
+ .scheduler = flask_scheduler,
+ .getdomaininfo = flask_getdomaininfo,
+ .getvcpucontext = flask_getvcpucontext,
+ .getvcpuinfo = flask_getvcpuinfo,
+ .domain_settime = flask_domain_settime,
+ .tbufcontrol = flask_tbufcontrol,
+ .readconsole = flask_readconsole,
+ .sched_id = flask_sched_id,
+ .setdomainmaxmem = flask_setdomainmaxmem,
+ .setdomainhandle = flask_setdomainhandle,
+ .setdebugging = flask_setdebugging,
+ .irq_permission = flask_irq_permission,
+ .iomem_permission = flask_iomem_permission,
+ .perfcontrol = flask_perfcontrol,
+
+ .evtchn_unbound = flask_evtchn_unbound,
+ .evtchn_interdomain = flask_evtchn_interdomain,
+ .evtchn_close_post = flask_evtchn_close_post,
+ .evtchn_send = flask_evtchn_send,
+ .evtchn_status = flask_evtchn_status,
+ .evtchn_reset = flask_evtchn_reset,
+
+ .grant_mapref = flask_grant_mapref,
+ .grant_unmapref = flask_grant_unmapref,
+ .grant_setup = flask_grant_setup,
+ .grant_transfer = flask_grant_transfer,
+ .grant_copy = flask_grant_copy,
+ .grant_query_size = flask_grant_query_size,
+
+ .alloc_security_domain = flask_domain_alloc_security,
+ .free_security_domain = flask_domain_free_security,
+ .alloc_security_evtchn = flask_alloc_security_evtchn,
+ .free_security_evtchn = flask_free_security_evtchn,
+
+ .translate_gpfn_list = flask_translate_gpfn_list,
+ .memory_adjust_reservation = flask_memory_adjust_reservation,
+ .memory_stat_reservation = flask_memory_stat_reservation,
+ .memory_pin_page = flask_memory_pin_page,
+ .update_va_mapping = flask_update_va_mapping,
+
+ .console_io = flask_console_io,
+
+ .profile = flask_profile,
+
+ .kexec = flask_kexec,
+ .schedop_shutdown = flask_schedop_shutdown,
+
+ .__do_xsm_op = do_flask_op,
+ .complete_init = flask_complete_init,
+
+#ifdef CONFIG_X86
+ .shadow_control = flask_shadow_control,
+ .ioport_permission = flask_ioport_permission,
+ .getpageframeinfo = flask_getpageframeinfo,
+ .getmemlist = flask_getmemlist,
+ .hypercall_init = flask_hypercall_init,
+ .hvmcontext = flask_hvmcontext,
+ .address_size = flask_address_size,
+ .hvm_param = flask_hvm_param,
+ .hvm_set_pci_intx_level = flask_hvm_set_pci_intx_level,
+ .hvm_set_isa_irq_level = flask_hvm_set_isa_irq_level,
+ .hvm_set_pci_link_route = flask_hvm_set_pci_link_route,
+ .apic = flask_apic,
+ .assign_vector = flask_assign_vector,
+ .xen_settime = flask_xen_settime,
+ .memtype = flask_memtype,
+ .microcode = flask_microcode,
+ .physinfo = flask_physinfo,
+ .platform_quirk = flask_platform_quirk,
+ .machine_memory_map = flask_machine_memory_map,
+ .domain_memory_map = flask_domain_memory_map,
+ .mmu_normal_update = flask_mmu_normal_update,
+ .mmu_machphys_update = flask_mmu_machphys_update,
+ .add_to_physmap = flask_add_to_physmap,
+#endif
+};
+
+static __init int flask_init(void)
+{
+ int ret = 0;
+
+ if ( !flask_enabled ) {
+ printk("Flask: Disabled at boot.\n");
+ return 0;
+ }
+
+ printk("Flask: Initializing.\n");
+
+ avc_init();
+
+ original_ops = xsm_ops;
+ if ( register_xsm(&flask_ops) )
+ panic("Flask: Unable to register with XSM.\n");
+
+ ret = security_load_policy(policy_buffer, policy_size);
+
+ if ( flask_enforcing )
+ printk("Flask: Starting in enforcing mode.\n");
+ else
+ printk("Flask: Starting in permissive mode.\n");
+
+ return ret;
+}
+
+xsm_initcall(flask_init);
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/av_inherit.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_inherit.h Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1 @@
+/* This file is automatically generated. Do not edit. */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/av_perm_to_string.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_perm_to_string.h Fri Aug 31 11:31:18 2007 +0100
@@ -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")
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/av_permissions.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/av_permissions.h Fri Aug 31 11:31:18 2007 +0100
@@ -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
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/avc.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/avc_ss.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/avc_ss.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/class_to_string.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/class_to_string.h Fri Aug 31 11:31:18 2007 +0100
@@ -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")
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/common_perm_to_string.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/common_perm_to_string.h Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1 @@
+/* This file is automatically generated. Do not edit. */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/conditional.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/conditional.h Fri Aug 31 11:31:18 2007 +0100
@@ -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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/flask.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/flask.h Fri Aug 31 11:31:18 2007 +0100
@@ -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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/initial_sid_to_string.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/initial_sid_to_string.h Fri Aug 31 11:31:18 2007 +0100
@@ -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",
+};
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/objsec.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/objsec.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/include/security.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/include/security.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/Makefile Fri Aug 31 11:31:18 2007 +0100
@@ -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
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/avtab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.c Fri Aug 31 11:31:18 2007 +0100
@@ -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;
+}
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/avtab.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/avtab.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/conditional.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.c Fri Aug 31 11:31:18 2007 +0100
@@ -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;
+}
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/conditional.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/conditional.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/constraint.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/constraint.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/context.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/context.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/ebitmap.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.c Fri Aug 31 11:31:18 2007 +0100
@@ -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;
+}
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/ebitmap.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/ebitmap.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/hashtab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.c Fri Aug 31 11:31:18 2007 +0100
@@ -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;
+}
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/hashtab.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/hashtab.h Fri Aug 31 11:31:18 2007 +0100
@@ -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 */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/mls.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.c Fri Aug 31 11:31:18 2007 +0100
@@ -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;
+}
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/mls.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls.h Fri Aug 31 11:31:18 2007 +0100
@@ -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 */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/mls_types.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/mls_types.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/policydb.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.c Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1798 @@
+/*
+ * Implementation of the policy database.
+ *
+ * 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> */
+
+#include <asm/byteorder.h>
+#include <xen/lib.h>
+#include <xen/types.h>
+#include <xen/xmalloc.h>
+#include <xen/string.h>
+#include <xen/errno.h>
+#include "security.h"
+
+#include "policydb.h"
+#include "conditional.h"
+#include "mls.h"
+
+#define _DEBUG_HASHES
+
+#ifdef DEBUG_HASHES
+static char *symtab_name[SYM_NUM] = {
+ "common prefixes",
+ "classes",
+ "roles",
+ "types",
+ "users",
+ "bools",
+ "levels",
+ "categories",
+};
+#endif
+
+int flask_mls_enabled = 0;
+
+static unsigned int symtab_sizes[SYM_NUM] = {
+ 2,
+ 32,
+ 16,
+ 512,
+ 128,
+ 16,
+ 16,
+ 16,
+};
+
+struct policydb_compat_info {
+ int version;
+ int sym_num;
+ int ocon_num;
+};
+
+/* These need to be updated if SYM_NUM or OCON_NUM changes */
+static struct policydb_compat_info policydb_compat[] = {
+ {
+ .version = POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM - 3,
+ .ocon_num = OCON_NUM - 1,
+ },
+ {
+ .version = POLICYDB_VERSION_BOOL,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM - 1,
+ },
+ {
+ .version = POLICYDB_VERSION_IPV6,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_NLCLASS,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_AVTAB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+};
+
+static struct policydb_compat_info *policydb_lookup_compat(int version)
+{
+ int i;
+ struct policydb_compat_info *info = NULL;
+
+ for ( i = 0; i < sizeof(policydb_compat)/sizeof(*info); i++ )
+ {
+ if ( policydb_compat[i].version == version )
+ {
+ info = &policydb_compat[i];
+ break;
+ }
+ }
+ return info;
+}
+
+/*
+ * Initialize the role table.
+ */
+static int roles_init(struct policydb *p)
+{
+ char *key = NULL;
+ int rc;
+ struct role_datum *role;
+
+ role = xmalloc(struct role_datum);
+ if ( !role )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(role, 0, sizeof(*role));
+ role->value = ++p->p_roles.nprim;
+ if ( role->value != OBJECT_R_VAL )
+ {
+ rc = -EINVAL;
+ goto out_free_role;
+ }
+ key = xmalloc_array(char, strlen(OBJECT_R)+1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto out_free_role;
+ }
+ strlcpy(key, OBJECT_R, strlen(OBJECT_R)+1);
+ rc = hashtab_insert(p->p_roles.table, key, role);
+ if ( rc )
+ goto out_free_key;
+out:
+ return rc;
+
+out_free_key:
+ xfree(key);
+out_free_role:
+ xfree(role);
+ goto out;
+}
+
+/*
+ * Initialize a policy database structure.
+ */
+static int policydb_init(struct policydb *p)
+{
+ int i, rc;
+
+ memset(p, 0, sizeof(*p));
+
+ for ( i = 0; i < SYM_NUM; i++ )
+ {
+ rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
+ if ( rc )
+ goto out_free_symtab;
+ }
+
+ rc = avtab_init(&p->te_avtab);
+ if ( rc )
+ goto out_free_symtab;
+
+ rc = roles_init(p);
+ if ( rc )
+ goto out_free_avtab;
+
+ rc = cond_policydb_init(p);
+ if ( rc )
+ goto out_free_avtab;
+
+out:
+ return rc;
+
+out_free_avtab:
+ avtab_destroy(&p->te_avtab);
+
+out_free_symtab:
+ for ( i = 0; i < SYM_NUM; i++ )
+ hashtab_destroy(p->symtab[i].table);
+ goto out;
+}
+
+/*
+ * The following *_index functions are used to
+ * define the val_to_name and val_to_struct arrays
+ * in a policy database structure. The val_to_name
+ * arrays are used when converting security context
+ * structures into string representations. The
+ * val_to_struct arrays are used when the attributes
+ * of a class, role, or user are needed.
+ */
+
+static int common_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct common_datum *comdatum;
+
+ comdatum = datum;
+ p = datap;
+ if ( !comdatum->value || comdatum->value > p->p_commons.nprim )
+ return -EINVAL;
+ p->p_common_val_to_name[comdatum->value - 1] = key;
+ return 0;
+}
+
+static int class_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct class_datum *cladatum;
+
+ cladatum = datum;
+ p = datap;
+ if ( !cladatum->value || cladatum->value > p->p_classes.nprim )
+ return -EINVAL;
+ p->p_class_val_to_name[cladatum->value - 1] = key;
+ p->class_val_to_struct[cladatum->value - 1] = cladatum;
+ return 0;
+}
+
+static int role_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct role_datum *role;
+
+ role = datum;
+ p = datap;
+ if ( !role->value || role->value > p->p_roles.nprim )
+ return -EINVAL;
+ p->p_role_val_to_name[role->value - 1] = key;
+ p->role_val_to_struct[role->value - 1] = role;
+ return 0;
+}
+
+static int type_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct type_datum *typdatum;
+
+ typdatum = datum;
+ p = datap;
+
+ if ( typdatum->primary )
+ {
+ if ( !typdatum->value || typdatum->value > p->p_types.nprim )
+ return -EINVAL;
+ p->p_type_val_to_name[typdatum->value - 1] = key;
+ }
+
+ return 0;
+}
+
+static int user_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct user_datum *usrdatum;
+
+ usrdatum = datum;
+ p = datap;
+ if ( !usrdatum->value || usrdatum->value > p->p_users.nprim )
+ return -EINVAL;
+ p->p_user_val_to_name[usrdatum->value - 1] = key;
+ p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
+ return 0;
+}
+
+static int sens_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct level_datum *levdatum;
+
+ levdatum = datum;
+ p = datap;
+
+ if ( !levdatum->isalias )
+ {
+ if ( !levdatum->level->sens || levdatum->level->sens >
+ p->p_levels.nprim )
+ return -EINVAL;
+ p->p_sens_val_to_name[levdatum->level->sens - 1] = key;
+ }
+
+ return 0;
+}
+
+static int cat_index(void *key, void *datum, void *datap)
+{
+ struct policydb *p;
+ struct cat_datum *catdatum;
+
+ catdatum = datum;
+ p = datap;
+
+ if ( !catdatum->isalias )
+ {
+ if ( !catdatum->value || catdatum->value > p->p_cats.nprim )
+ return -EINVAL;
+ p->p_cat_val_to_name[catdatum->value - 1] = key;
+ }
+
+ return 0;
+}
+
+static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+ common_index,
+ class_index,
+ role_index,
+ type_index,
+ user_index,
+ cond_index_bool,
+ sens_index,
+ cat_index,
+};
+
+/*
+ * Define the common val_to_name array and the class
+ * val_to_name and val_to_struct arrays in a policy
+ * database structure.
+ *
+ * Caller must clean up upon failure.
+ */
+static int policydb_index_classes(struct policydb *p)
+{
+ int rc;
+
+ p->p_common_val_to_name =
+ xmalloc_array(char *, p->p_commons.nprim);
+ if ( !p->p_common_val_to_name )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = hashtab_map(p->p_commons.table, common_index, p);
+ if ( rc )
+ goto out;
+
+ p->class_val_to_struct =
+ (void *)xmalloc_array(struct class_datum, p->p_classes.nprim);
+ if ( !p->class_val_to_struct )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p->p_class_val_to_name =
+ xmalloc_array(char *, p->p_classes.nprim);
+ if ( !p->p_class_val_to_name )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = hashtab_map(p->p_classes.table, class_index, p);
+out:
+ return rc;
+}
+
+#ifdef DEBUG_HASHES
+static void symtab_hash_eval(struct symtab *s)
+{
+ int i;
+
+ for ( i = 0; i < SYM_NUM; i++ )
+ {
+ struct hashtab *h = s[i].table;
+ struct hashtab_info info;
+
+ hashtab_stat(h, &info);
+ printk(KERN_INFO "%s: %d entries and %d/%d buckets used, "
+ "longest chain length %d\n", symtab_name[i], h->nel,
+ info.slots_used, h->size, info.max_chain_len);
+ }
+}
+#endif
+
+/*
+ * Define the other val_to_name and val_to_struct arrays
+ * in a policy database structure.
+ *
+ * Caller must clean up on failure.
+ */
+static int policydb_index_others(struct policydb *p)
+{
+ int i, rc = 0;
+
+ printk(KERN_INFO "security: %d users, %d roles, %d types, %d bools",
+ p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim);
+ if ( flask_mls_enabled )
+ printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim);
+
+ printk("\n");
+
+ printk(KERN_INFO "security: %d classes, %d rules\n",
+ p->p_classes.nprim, p->te_avtab.nel);
+
+#ifdef DEBUG_HASHES
+ avtab_hash_eval(&p->te_avtab, "rules");
+ symtab_hash_eval(p->symtab);
+#endif
+
+ p->role_val_to_struct =
+ (void *)xmalloc_array(struct role_datum, p->p_roles.nprim);
+ if ( !p->role_val_to_struct )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p->user_val_to_struct =
+ (void *)xmalloc_array(struct user_datum, p->p_users.nprim);
+ if ( !p->user_val_to_struct )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if ( cond_init_bool_indexes(p) )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ for ( i = SYM_ROLES; i < SYM_NUM; i++ )
+ {
+ p->sym_val_to_name[i] =
+ xmalloc_array(char *, p->symtab[i].nprim);
+ if ( !p->sym_val_to_name[i] )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ rc = hashtab_map(p->symtab[i].table, index_f[i], p);
+ if ( rc )
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+/*
+ * The following *_destroy functions are used to
+ * free any memory allocated for each kind of
+ * symbol data in the policy database.
+ */
+
+static int perm_destroy(void *key, void *datum, void *p)
+{
+ xfree(key);
+ xfree(datum);
+ return 0;
+}
+
+static int common_destroy(void *key, void *datum, void *p)
+{
+ struct common_datum *comdatum;
+
+ xfree(key);
+ comdatum = datum;
+ hashtab_map(comdatum->permissions.table, perm_destroy, NULL);
+ hashtab_destroy(comdatum->permissions.table);
+ xfree(datum);
+ return 0;
+}
+
+static int class_destroy(void *key, void *datum, void *p)
+{
+ struct class_datum *cladatum;
+ struct constraint_node *constraint, *ctemp;
+ struct constraint_expr *e, *etmp;
+
+ xfree(key);
+ cladatum = datum;
+ hashtab_map(cladatum->permissions.table, perm_destroy, NULL);
+ hashtab_destroy(cladatum->permissions.table);
+ constraint = cladatum->constraints;
+ while ( constraint )
+ {
+ e = constraint->expr;
+ while ( e )
+ {
+ ebitmap_destroy(&e->names);
+ etmp = e;
+ e = e->next;
+ xfree(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ xfree(ctemp);
+ }
+
+ constraint = cladatum->validatetrans;
+ while ( constraint )
+ {
+ e = constraint->expr;
+ while ( e )
+ {
+ ebitmap_destroy(&e->names);
+ etmp = e;
+ e = e->next;
+ xfree(etmp);
+ }
+ ctemp = constraint;
+ constraint = constraint->next;
+ xfree(ctemp);
+ }
+
+ xfree(cladatum->comkey);
+ xfree(datum);
+ return 0;
+}
+
+static int role_destroy(void *key, void *datum, void *p)
+{
+ struct role_datum *role;
+
+ xfree(key);
+ role = datum;
+ ebitmap_destroy(&role->dominates);
+ ebitmap_destroy(&role->types);
+ xfree(datum);
+ return 0;
+}
+
+static int type_destroy(void *key, void *datum, void *p)
+{
+ xfree(key);
+ xfree(datum);
+ return 0;
+}
+
+static int user_destroy(void *key, void *datum, void *p)
+{
+ struct user_datum *usrdatum;
+
+ xfree(key);
+ usrdatum = datum;
+ ebitmap_destroy(&usrdatum->roles);
+ ebitmap_destroy(&usrdatum->range.level[0].cat);
+ ebitmap_destroy(&usrdatum->range.level[1].cat);
+ ebitmap_destroy(&usrdatum->dfltlevel.cat);
+ xfree(datum);
+ return 0;
+}
+
+static int sens_destroy(void *key, void *datum, void *p)
+{
+ struct level_datum *levdatum;
+
+ xfree(key);
+ levdatum = datum;
+ ebitmap_destroy(&levdatum->level->cat);
+ xfree(levdatum->level);
+ xfree(datum);
+ return 0;
+}
+
+static int cat_destroy(void *key, void *datum, void *p)
+{
+ xfree(key);
+ xfree(datum);
+ return 0;
+}
+
+static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
+{
+ common_destroy,
+ class_destroy,
+ role_destroy,
+ type_destroy,
+ user_destroy,
+ cond_destroy_bool,
+ sens_destroy,
+ cat_destroy,
+};
+
+static void ocontext_destroy(struct ocontext *c, int i)
+{
+ context_destroy(&c->context[0]);
+ context_destroy(&c->context[1]);
+ if ( i == OCON_ISID )
+ xfree(c->u.name);
+ xfree(c);
+}
+
+/*
+ * Free any memory allocated by a policy database structure.
+ */
+void policydb_destroy(struct policydb *p)
+{
+ struct ocontext *c, *ctmp;
+ int i;
+ struct role_allow *ra, *lra = NULL;
+ struct role_trans *tr, *ltr = NULL;
+ struct range_trans *rt, *lrt = NULL;
+
+ for ( i = 0; i < SYM_NUM; i++ )
+ {
+ hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
+ hashtab_destroy(p->symtab[i].table);
+ }
+
+ for ( i = 0; i < SYM_NUM; i++ )
+ xfree(p->sym_val_to_name[i]);
+
+ xfree(p->class_val_to_struct);
+ xfree(p->role_val_to_struct);
+ xfree(p->user_val_to_struct);
+
+ avtab_destroy(&p->te_avtab);
+
+ for ( i = 0; i < OCON_NUM; i++ )
+ {
+ c = p->ocontexts[i];
+ while ( c )
+ {
+ ctmp = c;
+ c = c->next;
+ ocontext_destroy(ctmp,i);
+ }
+ }
+
+ cond_policydb_destroy(p);
+
+ for ( tr = p->role_tr; tr; tr = tr->next )
+ {
+ if ( ltr ) xfree(ltr);
+ ltr = tr;
+ }
+ if ( ltr ) xfree(ltr);
+
+ for ( ra = p->role_allow; ra; ra = ra -> next )
+ {
+ if ( lra ) xfree(lra);
+ lra = ra;
+ }
+ if ( lra ) xfree(lra);
+
+ for ( rt = p->range_tr; rt; rt = rt -> next )
+ {
+ if ( lrt ) xfree(lrt);
+ lrt = rt;
+ }
+ if ( lrt ) xfree(lrt);
+
+ for ( i = 0; i < p->p_types.nprim; i++ )
+ ebitmap_destroy(&p->type_attr_map[i]);
+ xfree(p->type_attr_map);
+
+ return;
+}
+
+/*
+ * Load the initial SIDs specified in a policy database
+ * structure into a SID table.
+ */
+int policydb_load_isids(struct policydb *p, struct sidtab *s)
+{
+ struct ocontext *head, *c;
+ int rc;
+
+ rc = sidtab_init(s);
+ if ( rc )
+ {
+ printk(KERN_ERR "security: out of memory on SID table init\n");
+ goto out;
+ }
+
+ head = p->ocontexts[OCON_ISID];
+ for ( c = head; c; c = c->next )
+ {
+ if ( !c->context[0].user )
+ {
+ printk(KERN_ERR "security: SID %s was never "
+ "defined.\n", c->u.name);
+ rc = -EINVAL;
+ goto out;
+ }
+ if ( sidtab_insert(s, c->sid[0], &c->context[0]) )
+ {
+ printk(KERN_ERR "security: unable to load initial "
+ "SID %s.\n", c->u.name);
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+/*
+ * Return 1 if the fields in the security context
+ * structure `c' are valid. Return 0 otherwise.
+ */
+int policydb_context_isvalid(struct policydb *p, struct context *c)
+{
+ struct role_datum *role;
+ struct user_datum *usrdatum;
+
+ if ( !c->role || c->role > p->p_roles.nprim )
+ return 0;
+
+ if ( !c->user || c->user > p->p_users.nprim )
+ return 0;
+
+ if ( !c->type || c->type > p->p_types.nprim )
+ return 0;
+
+ if ( c->role != OBJECT_R_VAL )
+ {
+ /*
+ * Role must be authorized for the type.
+ */
+ role = p->role_val_to_struct[c->role - 1];
+ if ( !ebitmap_get_bit(&role->types, c->type - 1) )
+ /* role may not be associated with type */
+ return 0;
+
+ /*
+ * User must be authorized for the role.
+ */
+ usrdatum = p->user_val_to_struct[c->user - 1];
+ if ( !usrdatum )
+ return 0;
+
+ if ( !ebitmap_get_bit(&usrdatum->roles, c->role - 1) )
+ /* user may not be associated with role */
+ return 0;
+ }
+
+ if ( !mls_context_isvalid(p, c) )
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Read a MLS range structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_range_helper(struct mls_range *r, void *fp)
+{
+ __le32 buf[2];
+ u32 items;
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto out;
+
+ items = le32_to_cpu(buf[0]);
+ if ( items > ARRAY_SIZE(buf) )
+ {
+ printk(KERN_ERR "security: mls: range overflow\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = next_entry(buf, fp, sizeof(u32) * items);
+ if ( rc < 0 )
+ {
+ printk(KERN_ERR "security: mls: truncated range\n");
+ goto out;
+ }
+ r->level[0].sens = le32_to_cpu(buf[0]);
+ if ( items > 1 )
+ r->level[1].sens = le32_to_cpu(buf[1]);
+ else
+ r->level[1].sens = r->level[0].sens;
+
+ rc = ebitmap_read(&r->level[0].cat, fp);
+ if ( rc )
+ {
+ printk(KERN_ERR "security: mls: error reading low "
+ "categories\n");
+ goto out;
+ }
+ if ( items > 1 )
+ {
+ rc = ebitmap_read(&r->level[1].cat, fp);
+ if ( rc )
+ {
+ printk(KERN_ERR "security: mls: error reading high "
+ "categories\n");
+ goto bad_high;
+ }
+ }
+ else
+ {
+ rc = ebitmap_cpy(&r->level[1].cat, &r->level[0].cat);
+ if ( rc )
+ {
+ printk(KERN_ERR "security: mls: out of memory\n");
+ goto bad_high;
+ }
+ }
+
+ rc = 0;
+out:
+ return rc;
+bad_high:
+ ebitmap_destroy(&r->level[0].cat);
+ goto out;
+}
+
+/*
+ * Read and validate a security context structure
+ * from a policydb binary representation file.
+ */
+static int context_read_and_validate(struct context *c, struct policydb *p,
+ void *fp)
+{
+ __le32 buf[3];
+ int rc;
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ {
+ printk(KERN_ERR "security: context truncated\n");
+ goto out;
+ }
+ c->user = le32_to_cpu(buf[0]);
+ c->role = le32_to_cpu(buf[1]);
+ c->type = le32_to_cpu(buf[2]);
+ if ( p->policyvers >= POLICYDB_VERSION_MLS )
+ {
+ if ( mls_read_range_helper(&c->range, fp) )
+ {
+ printk(KERN_ERR "security: error reading MLS range of "
+ "context\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+ if ( !policydb_context_isvalid(p, c) )
+ {
+ printk(KERN_ERR "security: invalid security context\n");
+ context_destroy(c);
+ rc = -EINVAL;
+ }
+out:
+ return rc;
+}
+
+/*
+ * The following *_read functions are used to
+ * read the symbol data from a policy database
+ * binary representation file.
+ */
+
+static int perm_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct perm_datum *perdatum;
+ int rc;
+ __le32 buf[2];
+ u32 len;
+
+ perdatum = xmalloc(struct perm_datum);
+ if ( !perdatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(perdatum, 0, sizeof(*perdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ perdatum->value = le32_to_cpu(buf[1]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ rc = hashtab_insert(h, key, perdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ perm_destroy(key, perdatum, NULL);
+ goto out;
+}
+
+static int common_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct common_datum *comdatum;
+ __le32 buf[4];
+ u32 len, nel;
+ int i, rc;
+
+ comdatum = xmalloc(struct common_datum);
+ if ( !comdatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(comdatum, 0, sizeof(*comdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ comdatum->value = le32_to_cpu(buf[1]);
+
+ rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
+ if ( rc )
+ goto bad;
+ comdatum->permissions.nprim = le32_to_cpu(buf[2]);
+ nel = le32_to_cpu(buf[3]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ for ( i = 0; i < nel; i++ )
+ {
+ rc = perm_read(p, comdatum->permissions.table, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ rc = hashtab_insert(h, key, comdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ common_destroy(key, comdatum, NULL);
+ goto out;
+}
+
+static int read_cons_helper(struct constraint_node **nodep, int ncons,
+ int allowxtarget, void *fp)
+{
+ struct constraint_node *c, *lc;
+ struct constraint_expr *e, *le;
+ __le32 buf[3];
+ u32 nexpr;
+ int rc, i, j, depth;
+
+ lc = NULL;
+ for ( i = 0; i < ncons; i++ )
+ {
+ c = xmalloc(struct constraint_node);
+ if ( !c )
+ return -ENOMEM;
+ memset(c, 0, sizeof(*c));
+
+ if ( lc )
+ {
+ lc->next = c;
+ }
+ else
+ {
+ *nodep = c;
+ }
+
+ rc = next_entry(buf, fp, (sizeof(u32) * 2));
+ if ( rc < 0 )
+ return rc;
+ c->permissions = le32_to_cpu(buf[0]);
+ nexpr = le32_to_cpu(buf[1]);
+ le = NULL;
+ depth = -1;
+ for ( j = 0; j < nexpr; j++ )
+ {
+ e = xmalloc(struct constraint_expr);
+ if ( !e )
+ return -ENOMEM;
+ memset(e, 0, sizeof(*e));
+
+ if ( le )
+ le->next = e;
+ else
+ c->expr = e;
+
+ rc = next_entry(buf, fp, (sizeof(u32) * 3));
+ if ( rc < 0 )
+ return rc;
+ e->expr_type = le32_to_cpu(buf[0]);
+ e->attr = le32_to_cpu(buf[1]);
+ e->op = le32_to_cpu(buf[2]);
+
+ switch ( e->expr_type )
+ {
+ case CEXPR_NOT:
+ if ( depth < 0 )
+ return -EINVAL;
+ break;
+ case CEXPR_AND:
+ case CEXPR_OR:
+ if ( depth < 1 )
+ return -EINVAL;
+ depth--;
+ break;
+ case CEXPR_ATTR:
+ if ( depth == (CEXPR_MAXDEPTH - 1) )
+ return -EINVAL;
+ depth++;
+ break;
+ case CEXPR_NAMES:
+ if ( !allowxtarget && (e->attr & CEXPR_XTARGET) )
+ return -EINVAL;
+ if ( depth == (CEXPR_MAXDEPTH - 1) )
+ return -EINVAL;
+ depth++;
+ if ( ebitmap_read(&e->names, fp) )
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ le = e;
+ }
+ if ( depth != 0 )
+ return -EINVAL;
+ lc = c;
+ }
+
+ return 0;
+}
+
+static int class_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct class_datum *cladatum;
+ __le32 buf[6];
+ u32 len, len2, ncons, nel;
+ int i, rc;
+
+ cladatum = xmalloc(struct class_datum);
+ if ( !cladatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(cladatum, 0, sizeof(*cladatum));
+
+ rc = next_entry(buf, fp, sizeof(u32)*6);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ len2 = le32_to_cpu(buf[1]);
+ cladatum->value = le32_to_cpu(buf[2]);
+
+ rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
+ if ( rc )
+ goto bad;
+ cladatum->permissions.nprim = le32_to_cpu(buf[3]);
+ nel = le32_to_cpu(buf[4]);
+
+ ncons = le32_to_cpu(buf[5]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ if ( len2 )
+ {
+ cladatum->comkey = xmalloc_array(char, len2 + 1);
+ if ( !cladatum->comkey )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(cladatum->comkey, fp, len2);
+ if ( rc < 0 )
+ goto bad;
+ cladatum->comkey[len2] = 0;
+
+ cladatum->comdatum = hashtab_search(p->p_commons.table,
+ cladatum->comkey);
+ if ( !cladatum->comdatum )
+ {
+ printk(KERN_ERR "security: unknown common %s\n",
+ cladatum->comkey);
+ rc = -EINVAL;
+ goto bad;
+ }
+ }
+ for ( i = 0; i < nel; i++ )
+ {
+ rc = perm_read(p, cladatum->permissions.table, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+ if ( rc )
+ goto bad;
+
+ if ( p->policyvers >= POLICYDB_VERSION_VALIDATETRANS )
+ {
+ /* grab the validatetrans rules */
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ ncons = le32_to_cpu(buf[0]);
+ rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ rc = hashtab_insert(h, key, cladatum);
+ if ( rc )
+ goto bad;
+
+ rc = 0;
+out:
+ return rc;
+bad:
+ class_destroy(key, cladatum, NULL);
+ goto out;
+}
+
+static int role_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct role_datum *role;
+ int rc;
+ __le32 buf[2];
+ u32 len;
+
+ role = xmalloc(struct role_datum);
+ if ( !role )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(role, 0, sizeof(*role));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ role->value = le32_to_cpu(buf[1]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ rc = ebitmap_read(&role->dominates, fp);
+ if ( rc )
+ goto bad;
+
+ rc = ebitmap_read(&role->types, fp);
+ if ( rc )
+ goto bad;
+
+ if ( strcmp(key, OBJECT_R) == 0 )
+ {
+ if ( role->value != OBJECT_R_VAL )
+ {
+ printk(KERN_ERR "Role %s has wrong value %d\n", OBJECT_R,
+ role->value);
+ rc = -EINVAL;
+ goto bad;
+ }
+ rc = 0;
+ goto bad;
+ }
+
+ rc = hashtab_insert(h, key, role);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ role_destroy(key, role, NULL);
+ goto out;
+}
+
+static int type_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct type_datum *typdatum;
+ int rc;
+ __le32 buf[3];
+ u32 len;
+
+ typdatum = xmalloc(struct type_datum);
+ if ( !typdatum )
+ {
+ rc = -ENOMEM;
+ return rc;
+ }
+ memset(typdatum, 0, sizeof(*typdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ typdatum->value = le32_to_cpu(buf[1]);
+ typdatum->primary = le32_to_cpu(buf[2]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ rc = hashtab_insert(h, key, typdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ type_destroy(key, typdatum, NULL);
+ goto out;
+}
+
+
+/*
+ * Read a MLS level structure from a policydb binary
+ * representation file.
+ */
+static int mls_read_level(struct mls_level *lp, void *fp)
+{
+ __le32 buf[1];
+ int rc;
+
+ memset(lp, 0, sizeof(*lp));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ {
+ printk(KERN_ERR "security: mls: truncated level\n");
+ goto bad;
+ }
+ lp->sens = le32_to_cpu(buf[0]);
+
+ if ( ebitmap_read(&lp->cat, fp) )
+ {
+ printk(KERN_ERR "security: mls: error reading level categories\n");
+ goto bad;
+ }
+ return 0;
+
+bad:
+ return -EINVAL;
+}
+
+static int user_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct user_datum *usrdatum;
+ int rc;
+ __le32 buf[2];
+ u32 len;
+
+ usrdatum = xmalloc(struct user_datum);
+ if ( !usrdatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(usrdatum, 0, sizeof(*usrdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ usrdatum->value = le32_to_cpu(buf[1]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ rc = ebitmap_read(&usrdatum->roles, fp);
+ if ( rc )
+ goto bad;
+
+ if ( p->policyvers >= POLICYDB_VERSION_MLS )
+ {
+ rc = mls_read_range_helper(&usrdatum->range, fp);
+ if ( rc )
+ goto bad;
+ rc = mls_read_level(&usrdatum->dfltlevel, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ rc = hashtab_insert(h, key, usrdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ user_destroy(key, usrdatum, NULL);
+ goto out;
+}
+
+static int sens_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct level_datum *levdatum;
+ int rc;
+ __le32 buf[2];
+ u32 len;
+
+ levdatum = xmalloc(struct level_datum);
+ if ( !levdatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(levdatum, 0, sizeof(*levdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ levdatum->isalias = le32_to_cpu(buf[1]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ levdatum->level = xmalloc(struct mls_level);
+ if ( !levdatum->level )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ if ( mls_read_level(levdatum->level, fp) )
+ {
+ rc = -EINVAL;
+ goto bad;
+ }
+
+ rc = hashtab_insert(h, key, levdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+bad:
+ sens_destroy(key, levdatum, NULL);
+ goto out;
+}
+
+static int cat_read(struct policydb *p, struct hashtab *h, void *fp)
+{
+ char *key = NULL;
+ struct cat_datum *catdatum;
+ int rc;
+ __le32 buf[3];
+ u32 len;
+
+ catdatum = xmalloc(struct cat_datum);
+ if ( !catdatum )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(catdatum, 0, sizeof(*catdatum));
+
+ rc = next_entry(buf, fp, sizeof buf);
+ if ( rc < 0 )
+ goto bad;
+
+ len = le32_to_cpu(buf[0]);
+ catdatum->value = le32_to_cpu(buf[1]);
+ catdatum->isalias = le32_to_cpu(buf[2]);
+
+ key = xmalloc_array(char, len + 1);
+ if ( !key )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(key, fp, len);
+ if ( rc < 0 )
+ goto bad;
+ key[len] = 0;
+
+ rc = hashtab_insert(h, key, catdatum);
+ if ( rc )
+ goto bad;
+out:
+ return rc;
+
+bad:
+ cat_destroy(key, catdatum, NULL);
+ goto out;
+}
+
+static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) =
+{
+ common_read,
+ class_read,
+ role_read,
+ type_read,
+ user_read,
+ cond_read_bool,
+ sens_read,
+ cat_read,
+};
+
+extern int ss_initialized;
+
+/*
+ * Read the configuration data from a policy database binary
+ * representation file into a policy database structure.
+ */
+int policydb_read(struct policydb *p, void *fp)
+{
+ struct role_allow *ra, *lra;
+ struct role_trans *tr, *ltr;
+ struct ocontext *l, *c /*, *newc*/;
+ int i, j, rc;
+ __le32 buf[8];
+ u32 len, /*len2,*/ config, nprim, nel /*, nel2*/;
+ char *policydb_str;
+ struct policydb_compat_info *info;
+ struct range_trans *rt, *lrt;
+
+ config = 0;
+ rc = policydb_init(p);
+ if ( rc )
+ goto out;
+
+ /* Read the magic number and string length. */
+ rc = next_entry(buf, fp, sizeof(u32)* 2);
+ if ( rc < 0 )
+ goto bad;
+
+ if ( le32_to_cpu(buf[0]) != POLICYDB_MAGIC )
+ {
+ printk(KERN_ERR "security: policydb magic number 0x%x does "
+ "not match expected magic number 0x%x\n",
+ le32_to_cpu(buf[0]), POLICYDB_MAGIC);
+ goto bad;
+ }
+
+ len = le32_to_cpu(buf[1]);
+ if ( len != strlen(POLICYDB_STRING) )
+ {
+ printk(KERN_ERR "security: policydb string length %d does not "
+ "match expected length %Zu\n",
+ len, (u32) strlen(POLICYDB_STRING));
+ goto bad;
+ }
+ policydb_str = xmalloc_array(char, len + 1);
+ if ( !policydb_str )
+ {
+ printk(KERN_ERR "security: unable to allocate memory for policydb "
+ "string of length %d\n", len);
+ rc = -ENOMEM;
+ goto bad;
+ }
+ rc = next_entry(policydb_str, fp, len);
+ if ( rc < 0 )
+ {
+ printk(KERN_ERR "security: truncated policydb string identifier\n");
+ xfree(policydb_str);
+ goto bad;
+ }
+ policydb_str[len] = 0;
+ if ( strcmp(policydb_str, POLICYDB_STRING) )
+ {
+ printk(KERN_ERR "security: policydb string %s does not match "
+ "my string %s\n", policydb_str, POLICYDB_STRING);
+ xfree(policydb_str);
+ goto bad;
+ }
+ /* Done with policydb_str. */
+ xfree(policydb_str);
+ policydb_str = NULL;
+
+ /* Read the version, config, and table sizes. */
+ rc = next_entry(buf, fp, sizeof(u32)*4);
+ if ( rc < 0 )
+ goto bad;
+
+ p->policyvers = le32_to_cpu(buf[0]);
+ if ( p->policyvers < POLICYDB_VERSION_MIN ||
+ p->policyvers > POLICYDB_VERSION_MAX )
+ {
+ printk(KERN_ERR "security: policydb version %d does not match "
+ "my version range %d-%d\n",
+ le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+ goto bad;
+ }
+
+ if ( (le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS) )
+ {
+ if ( ss_initialized && !flask_mls_enabled )
+ {
+ printk(KERN_ERR "Cannot switch between non-MLS and MLS "
+ "policies\n");
+ goto bad;
+ }
+ flask_mls_enabled = 1;
+ config |= POLICYDB_CONFIG_MLS;
+
+ if ( p->policyvers < POLICYDB_VERSION_MLS )
+ {
+ printk(KERN_ERR "security policydb version %d (MLS) "
+ "not backwards compatible\n", p->policyvers);
+ goto bad;
+ }
+ }
+ else
+ {
+ if ( ss_initialized && flask_mls_enabled )
+ {
+ printk(KERN_ERR "Cannot switch between MLS and non-MLS "
+ "policies\n");
+ goto bad;
+ }
+ }
+
+ info = policydb_lookup_compat(p->policyvers);
+ if ( !info )
+ {
+ printk(KERN_ERR "security: unable to find policy compat info "
+ "for version %d\n", p->policyvers);
+ goto bad;
+ }
+
+ if ( le32_to_cpu(buf[2]) != info->sym_num ||
+ le32_to_cpu(buf[3]) != info->ocon_num )
+ {
+ printk(KERN_ERR "security: policydb table sizes (%d,%d) do "
+ "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
+ le32_to_cpu(buf[3]),
+ info->sym_num, info->ocon_num);
+ goto bad;
+ }
+
+ for ( i = 0; i < info->sym_num; i++ )
+ {
+ rc = next_entry(buf, fp, sizeof(u32)*2);
+ if ( rc < 0 )
+ goto bad;
+ nprim = le32_to_cpu(buf[0]);
+ nel = le32_to_cpu(buf[1]);
+ for ( j = 0; j < nel; j++ )
+ {
+ rc = read_f[i](p, p->symtab[i].table, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ p->symtab[i].nprim = nprim;
+ }
+
+ rc = avtab_read(&p->te_avtab, fp, p->policyvers);
+ if ( rc )
+ goto bad;
+
+ if ( p->policyvers >= POLICYDB_VERSION_BOOL )
+ {
+ rc = cond_read_list(p, fp);
+ if ( rc )
+ goto bad;
+ }
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ ltr = NULL;
+ for ( i = 0; i < nel; i++ )
+ {
+ tr = xmalloc(struct role_trans);
+ if ( !tr )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(tr, 0, sizeof(*tr));
+ if ( ltr )
+ ltr->next = tr;
+ else
+ p->role_tr = tr;
+ rc = next_entry(buf, fp, sizeof(u32)*3);
+ if ( rc < 0 )
+ goto bad;
+ tr->role = le32_to_cpu(buf[0]);
+ tr->type = le32_to_cpu(buf[1]);
+ tr->new_role = le32_to_cpu(buf[2]);
+ ltr = tr;
+ }
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ lra = NULL;
+ for ( i = 0; i < nel; i++ )
+ {
+ ra = xmalloc(struct role_allow);
+ if ( !ra )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(ra, 0, sizeof(*ra));
+ if ( lra )
+ lra->next = ra;
+ else
+ p->role_allow = ra;
+ rc = next_entry(buf, fp, sizeof(u32)*2);
+ if ( rc < 0 )
+ goto bad;
+ ra->role = le32_to_cpu(buf[0]);
+ ra->new_role = le32_to_cpu(buf[1]);
+ lra = ra;
+ }
+
+ rc = policydb_index_classes(p);
+ if ( rc )
+ goto bad;
+
+ rc = policydb_index_others(p);
+ if ( rc )
+ goto bad;
+
+ for ( i = 0; i < info->ocon_num; i++ )
+ {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ l = NULL;
+ for ( j = 0; j < nel; j++ )
+ {
+ c = xmalloc(struct ocontext);
+ if ( !c )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(c, 0, sizeof(*c));
+ if ( l )
+ l->next = c;
+ else
+ p->ocontexts[i] = c;
+ l = c;
+ rc = -EINVAL;
+ switch ( i )
+ {
+ case OCON_ISID:
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ c->sid[0] = le32_to_cpu(buf[0]);
+ rc = context_read_and_validate(&c->context[0], p, fp);
+ if ( rc )
+ goto bad;
+ break;
+ }
+ }
+ }
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+
+ if ( p->policyvers >= POLICYDB_VERSION_MLS )
+ {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if ( rc < 0 )
+ goto bad;
+ nel = le32_to_cpu(buf[0]);
+ lrt = NULL;
+ for ( i = 0; i < nel; i++ )
+ {
+ rt = xmalloc(struct range_trans);
+ if ( !rt )
+ {
+ rc = -ENOMEM;
+ goto bad;
+ }
+ memset(rt, 0, sizeof(*rt));
+ if ( lrt )
+ lrt->next = rt;
+ else
+ p->range_tr = rt;
+ rc = next_entry(buf, fp, (sizeof(u32) * 2));
+ if ( rc < 0 )
+ goto bad;
+ rt->dom = le32_to_cpu(buf[0]);
+ rt->type = le32_to_cpu(buf[1]);
+ rc = mls_read_range_helper(&rt->range, fp);
+ if ( rc )
+ goto bad;
+ lrt = rt;
+ }
+ }
+
+ p->type_attr_map = xmalloc_array(struct ebitmap, p->p_types.nprim);
+ if ( !p->type_attr_map )
+ goto bad;
+
+ for ( i = 0; i < p->p_types.nprim; i++ )
+ {
+ ebitmap_init(&p->type_attr_map[i]);
+ if ( p->policyvers >= POLICYDB_VERSION_AVTAB )
+ {
+ if ( ebitmap_read(&p->type_attr_map[i], fp) )
+ goto bad;
+ }
+ /* add the type itself as the degenerate case */
+ if ( ebitmap_set_bit(&p->type_attr_map[i], i, 1) )
+ goto bad;
+ }
+
+ rc = 0;
+out:
+ return rc;
+bad:
+ if ( !rc )
+ rc = -EINVAL;
+ policydb_destroy(p);
+ goto out;
+}
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/policydb.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/policydb.h Fri Aug 31 11:31:18 2007 +0100
@@ -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_ */
+
diff -r 96f64f4c42f0 -r 6c8c934b235c xen/xsm/flask/ss/services.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/xsm/flask/ss/services.c Fri Aug 31 11:31:18 2007 +0100
@@ -0,0 +1,1657 @@
+/*
+ * Implementation of the security services.
+ *
+ * Authors : Stephen Smalley, <sds@epoch.ncsc.mil>
+ * James Morris <jmorris@redhat.com>
+ *
+ * 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
+ * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+/* 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/spinlock.h>
+#include <xen/errno.h>
+#include "flask.h"
+#include "avc.h"
+#include "avc_ss.h"
+#include "security.h"
+#include "context.h"
+#include "policydb.h"
+#include "sidtab.h"
+#include "services.h"
+#include "conditional.h"
+#include "mls.h"
+
+unsigned int policydb_loaded_version;
+
+static DEFINE_RWLOCK(policy_rwlock);
+#define POLICY_RDLOCK read_lock(&policy_rwlock)
+#define POLICY_WRLOCK write_lock_irq(&policy_rwlock)
+#define POLICY_RDUNLOCK read_unlock(&policy_rwlock)
+#define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock)
+
+static DEFINE_SPINLOCK(load_sem);
+#define LOAD_LOCK spin_lock(&load_sem)
+#define LOAD_UNLOCK spin_unlock(&load_sem)
+
+static struct sidtab sidtab;
+struct policydb policydb;
+int ss_initialized = 0;
+
+/*
+ * The largest sequence number that has been used when
+ * providing an access decision to the access vector cache.
+ * The sequence number only changes when a policy change
+ * occurs.
+ */
+static u32 latest_granting = 0;
+
+/* Forward declaration. */
+static int context_struct_to_string(struct context *context, char **scontext,
+ u32 *scontext_len);
+
+/*
+ * Return the boolean value of a constraint expression
+ * when it is applied to the specified source and target
+ * security contexts.
+ *
+ * xcontext is a special beast... It is used by the validatetrans rules
+ * only. For these rules, scontext is the context before the transition,
+ * tcontext is the context after the transition, and xcontext is the context
+ * of the process performing the transition. All other callers of
+ * constraint_expr_eval should pass in NULL for xcontext.
+ */
+static int constraint_expr_eval(struct context *scontext,
+ struct context *tcontext, struct context *xcontext,
+ struct constraint_expr *cexpr)
+{
+ u32 val1, val2;
+ struct context *c;
+ struct role_datum *r1, *r2;
+ struct mls_level *l1, *l2;
+ struct constraint_expr *e;
+ int s[CEXPR_MAXDEPTH];
+ int sp = -1;
+
+ for ( e = cexpr; e; e = e->next )
+ {
+ switch ( e->expr_type )
+ {
+ case CEXPR_NOT:
+ BUG_ON(sp < 0);
+ s[sp] = !s[sp];
+ break;
+ case CEXPR_AND:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] &= s[sp+1];
+ break;
+ case CEXPR_OR:
+ BUG_ON(sp < 1);
+ sp--;
+ s[sp] |= s[sp+1];
+ break;
+ case CEXPR_ATTR:
+ if ( sp == (CEXPR_MAXDEPTH-1) )
+ return 0;
+ switch ( e->attr )
+ {
+ case CEXPR_USER:
+ val1 = scontext->user;
+ val2 = tcontext->user;
+ break;
+ case CEXPR_TYPE:
+ val1 = scontext->type;
+ val2 = tcontext->type;
+ break;
+ case CEXPR_ROLE:
+ val1 = scontext->role;
+ val2 = tcontext->role;
+ r1 = policydb.role_val_to_struct[val1 - 1];
+ r2 = policydb.role_val_to_struct[val2 - 1];
+ switch ( e->op )
+ {
+ case CEXPR_DOM:
+ s[++sp] = ebitmap_get_bit(&r1->dominates, val2 - 1);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = ebitmap_get_bit(&r2->dominates, val1 - 1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = ( !ebitmap_get_bit(&r1->dominates,
+ val2 - 1) &&
+ !ebitmap_get_bit(&r2->dominates,
+ val1 - 1) );
+ continue;
+ default:
+ break;
+ }
+ break;
+ case CEXPR_L1L2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_L1H2:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_H1L2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[0]);
+ goto mls_ops;
+ case CEXPR_H1H2:
+ l1 = &(scontext->range.level[1]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L1H1:
+ l1 = &(scontext->range.level[0]);
+ l2 = &(scontext->range.level[1]);
+ goto mls_ops;
+ case CEXPR_L2H2:
+ l1 = &(tcontext->range.level[0]);
+ l2 = &(tcontext->range.level[1]);
+ goto mls_ops;
+mls_ops:
+ switch ( e->op )
+ {
+ case CEXPR_EQ:
+ s[++sp] = mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_NEQ:
+ s[++sp] = !mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_DOM:
+ s[++sp] = mls_level_dom(l1, l2);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = mls_level_dom(l2, l1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = mls_level_incomp(l2, l1);
+ continue;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+
+ switch ( e->op )
+ {
+ case CEXPR_EQ:
+ s[++sp] = (val1 == val2);
+ break;
+ case CEXPR_NEQ:
+ s[++sp] = (val1 != val2);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ case CEXPR_NAMES:
+ if ( sp == (CEXPR_MAXDEPTH-1) )
+ return 0;
+ c = scontext;
+ if ( e->attr & CEXPR_TARGET )
+ c = tcontext;
+ else if ( e->attr & CEXPR_XTARGET )
+ {
+ c = xcontext;
+ if ( !c )
+ {
+ BUG();
+ return 0;
+ }
+ }
+ if ( e->attr & CEXPR_USER )
+ val1 = c->user;
+ else if ( e->attr & CEXPR_ROLE )
+ val1 = c->role;
+ else if ( e->attr & CEXPR_TYPE )
+ val1 = c->type;
+ else
+ {
+ BUG();
+ return 0;
+ }
+
+ switch ( e->op )
+ {
+ case CEXPR_EQ:
+ s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
+ break;
+ case CEXPR_NEQ:
+ s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ return 0;
+ }
+ }
+
+ BUG_ON(sp != 0);
+ return s[0];
+}
+
+/*
+ * Compute access vectors based on a context structure pair for
+ * the permissions in a particular class.
+ */
+static int context_struct_compute_av(struct context *scontext,
+ struct context *tcontext, u16 tclass, u32 requested,
+ struct av_decision *avd)
+{
+ struct constraint_node *constraint;
+ struct role_allow *ra;
+ struct avtab_key avkey;
+ struct avtab_node *node;
+ struct class_datum *tclass_datum;
+ struct ebitmap *sattr, *tattr;
+ struct ebitmap_node *snode, *tnode;
+ unsigned int i, j;
+
+ if ( !tclass || tclass > policydb.p_classes.nprim )
+ {
+ printk(KERN_ERR "security_compute_av: unrecognized class %d\n",
+ tclass);
+ return -EINVAL;
+ }
+ tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+ /*
+ * Initialize the access vectors to the default values.
+ */
+ avd->allowed = 0;
+ avd->decided = 0xffffffff;
+ avd->auditallow = 0;
+ avd->auditdeny = 0xffffffff;
+ avd->seqno = latest_granting;
+
+ /*
+ * If a specific type enforcement rule was defined for
+ * this permission check, then use it.
+ */
+ avkey.target_class = tclass;
+ avkey.specified = AVTAB_AV;
+ sattr = &policydb.type_attr_map[scontext->type - 1];
+ tattr = &policydb.type_attr_map[tcontext->type - 1];
+ ebitmap_for_each_bit(sattr, snode, i)
+ {
+ if ( !ebitmap_node_get_bit(snode, i) )
+ continue;
+ ebitmap_for_each_bit(tattr, tnode, j)
+ {
+ if ( !ebitmap_node_get_bit(tnode, j) )
+ continue;
+ avkey.source_type = i + 1;
+ avkey.target_type = j + 1;
+ for ( node = avtab_search_node(&policydb.te_avtab, &avkey);
+ node != NULL;
+ node = avtab_search_node_next(node, avkey.specified) )
+ {
+ if ( node->key.specified == AVTAB_ALLOWED )
+ avd->allowed |= node->datum.data;
+ else if ( node->key.specified == AVTAB_AUDITALLOW )
+ avd->auditallow |= node->datum.data;
+ else if ( node->key.specified == AVTAB_AUDITDENY )
+ avd->auditdeny &= node->datum.data;
+ }
+
+ /* Check conditional av table for additional permissions */
+ cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
+
+ }
+ }
+
+ /*
+ * Remove any permissions prohibited by a constraint (this includes
+ * the MLS policy).
+ */
+ constraint = tclass_datum->constraints;
+ while ( constraint )
+ {
+ if ( (constraint->permissions & (avd->allowed) ) &&
+ !constraint_expr_eval(scontext, tcontext, NULL, constraint->expr))
+ {
+ avd->allowed = (avd->allowed) & ~(constraint->permissions);
+ }
+ constraint = constraint->next;
+ }
+
+ /*
+ * If checking process transition permission and the
+ * role is changing, then check the (current_role, new_role)
+ * pair.
+ */
+ if ( tclass == SECCLASS_DOMAIN &&
+/* removed until future dynamic domain capability
+ (avd->allowed & (DOMAIN__TRANSITION | DOMAIN__DYNTRANSITION)) &&
+*/
+ scontext->role != tcontext->role )
+ {
+ for ( ra = policydb.role_allow; ra; ra = ra->next )
+ {
+ if ( scontext->role == ra->role && tcontext->role == ra->new_role )
+ break;
+ }
+/* removed until future dynamic domain capability
+ if (!ra)
+ avd->allowed = (avd->allowed) & ~(DOMAIN__TRANSITION |
+ DOMAIN__DYNTRANSITION);
+*/
+ }
+
+ return 0;
+}
+
+static int security_validtrans_handle_fail(struct context *ocontext,
+ struct context *ncontext, struct context *tcontext, u16 tclass)
+{
+ char *o = NULL, *n = NULL, *t = NULL;
+ u32 olen, nlen, tlen;
+
+ if ( context_struct_to_string(ocontext, &o, &olen) < 0 )
+ goto out;
+ if ( context_struct_to_string(ncontext, &n, &nlen) < 0 )
+ goto out;
+ if ( context_struct_to_string(tcontext, &t, &tlen) < 0 )
+ goto out;
+ printk("security_validate_transition: denied for"
+ " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
+ o, n, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+ xfree(o);
+ xfree(n);
+ xfree(t);
+
+ if ( !flask_enforcing )
+ return 0;
+ return -EPERM;
+}
+
+int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
+ u16 tclass)
+{
+ struct context *ocontext;
+ struct context *ncontext;
+ struct context *tcontext;
+ struct class_datum *tclass_datum;
+ struct constraint_node *constraint;
+ int rc = 0;
+
+ if ( !ss_initialized )
+ return 0;
+
+ POLICY_RDLOCK;
+
+ if ( !tclass || tclass > policydb.p_classes.nprim )
+ {
+ printk(KERN_ERR "security_validate_transition: "
+ "unrecognized class %d\n", tclass);
+ rc = -EINVAL;
+ goto out;
+ }
+ tclass_datum = policydb.class_val_to_struct[tclass - 1];
+
+ ocontext = sidtab_search(&sidtab, oldsid);
+ if ( !ocontext )
+ {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", oldsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ncontext = sidtab_search(&sidtab, newsid);
+ if ( !ncontext )
+ {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", newsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ tcontext = sidtab_search(&sidtab, tasksid);
+ if ( !tcontext )
+ {
+ printk(KERN_ERR "security_validate_transition: "
+ " unrecognized SID %d\n", tasksid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ constraint = tclass_datum->validatetrans;
+ while ( constraint )
+ {
+ if ( !constraint_expr_eval(ocontext, ncontext, tcontext,
+ constraint->expr) )
+ {
+ rc = security_validtrans_handle_fail(ocontext, ncontext,
+ tcontext, tclass);
+ goto out;
+ }
+ constraint = constraint->next;
+ }
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
+/**
+ * security_compute_av - Compute access vector decisions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ *
+ * Compute a set of access vector decisions based on the
+ * SID pair (@ssid, @tsid) for the permissions in @tclass.
+ * Return -%EINVAL if any of the parameters are invalid or %0
+ * if the access vector decisions were computed successfully.
+ */
+int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+ struct av_decision *avd)
+{
+ struct context *scontext = NULL, *tcontext = NULL;
+ int rc = 0;
+
+ if ( !ss_initialized )
+ {
+ avd->allowed = 0xffffffff;
+ avd->decided = 0xffffffff;
+ avd->auditallow = 0;
+ avd->auditdeny = 0xffffffff;
+ avd->seqno = latest_granting;
+ return 0;
+ }
+
+ POLICY_RDLOCK;
+
+ scontext = sidtab_search(&sidtab, ssid);
+ if ( !scontext )
+ {
+ printk("security_compute_av: unrecognized SID %d\n", ssid);
+ rc = -EINVAL;
+ goto out;
+ }
+ tcontext = sidtab_search(&sidtab, tsid);
+ if ( !tcontext )
+ {
+ printk("security_compute_av: unrecognized SID %d\n", tsid);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = context_struct_compute_av(scontext, tcontext, tclass, requested, avd);
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
+/*
+ * Write the security context string representation of
+ * the context structure `context' into a dynamically
+ * allocated string of the correct size. Set `*scontext'
+ * to point to this string and set `*scontext_len' to
+ * the length of the string.
+ */
+static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len)
+{
+ char *scontextp;
+
+ *scontext = NULL;
+ *scontext_len = 0;
+
+ /* Compute the size of the context. */
+ *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1;
+ *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1;
+ *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+ *scontext_len += mls_compute_context_len(context);
+
+ /* Allocate space for the context; caller must free this space. */
+ scontextp = xmalloc_array(char, *scontext_len);
+ if ( !scontextp )
+ return -ENOMEM;
+
+ *scontext = scontextp;
+
+ /*
+ * Copy the user name, role name and type name into the context.
+ */
+ snprintf(scontextp, *scontext_len, "%s:%s:%s",
+ policydb.p_user_val_to_name[context->user - 1],
+ policydb.p_role_val_to_name[context->role - 1],
+ policydb.p_type_val_to_name[context->type - 1]);
+ scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) +
+ 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) +
+ 1 + strlen(policydb.p_type_val_to_name[context->type - 1]);
+
+ mls_sid_to_context(context, &scontextp);
+
+ *scontextp = 0;
+
+ return 0;
+}
+
+#include "initial_sid_to_string.h"
+
+/**
+ * security_sid_to_context - Obtain a context for a given SID.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size. Set @scontext
+ * to point to this string and set @scontext_len to the length of the string.
+ */
+int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
+{
+ struct context *context;
+ int rc = 0;
+
+ if ( !ss_initialized )
+ {
+ if ( sid <= SECINITSID_NUM )
+ {
+ char *scontextp;
+
+ *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+ scontextp = xmalloc_array(char, *scontext_len);
+ strlcpy(scontextp, initial_sid_to_string[sid], *scontext_len);
+ *scontext = scontextp;
+ goto out;
+ }
+ printk(KERN_ERR "security_sid_to_context: called before initial "
+ "load_policy on unknown SID %d\n", sid);
+ rc = -EINVAL;
+ goto out;
+ }
+ POLICY_RDLOCK;
+ context = sidtab_search(&sidtab, sid);
+ if ( !context )
+ {
+ printk(KERN_ERR "security_sid_to_context: unrecognized SID "
+ "%d\n", sid);
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+ rc = context_struct_to_string(context, scontext, scontext_len);
+out_unlock:
+ POLICY_RDUNLOCK;
+out:
+ return rc;
+
+}
+
+static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+ char *scontext2;
+ struct context context;
+ struct role_datum *role;
+ struct type_datum *typdatum;
+ struct user_datum *usrdatum;
+ char *scontextp, *p, oldc;
+ int rc = 0;
+
+ if ( !ss_initialized )
+ {
+ int i;
+
+ for ( i = 1; i < SECINITSID_NUM; i++ )
+ {
+ if ( !strcmp(initial_sid_to_string[i], scontext) )
+ {
+ *sid = i;
+ goto out;
+ }
+ }
+ *sid = SECINITSID_XEN;
+ goto out;
+ }
+ *sid = SECSID_NULL;
+
+ /* Copy the string so that we can modify the copy as we parse it.
+ The string should already by null terminated, but we append a
+ null suffix to the copy to avoid problems with the existing
+ attr package, which doesn't view the null terminator as part
+ of the attribute value. */
+ scontext2 = xmalloc_array(char, scontext_len+1);
+ if ( !scontext2 )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memcpy(scontext2, scontext, scontext_len);
+ scontext2[scontext_len] = 0;
+
+ context_init(&context);
+ *sid = SECSID_NULL;
+
+ POLICY_RDLOCK;
+
+ /* Parse the security context. */
+
+ rc = -EINVAL;
+ scontextp = (char *) scontext2;
+
+ /* Extract the user. */
+ p = scontextp;
+ while ( *p && *p != ':' )
+ p++;
+
+ if (*p == 0)
+ goto out_unlock;
+
+ *p++ = 0;
+
+ usrdatum = hashtab_search(policydb.p_users.table, scontextp);
+ if ( !usrdatum )
+ goto out_unlock;
+
+ context.user = usrdatum->value;
+
+ /* Extract role. */
+ scontextp = p;
+ while ( *p && *p != ':' )
+ p++;
+
+ if ( *p == 0 )
+ goto out_unlock;
+
+ *p++ = 0;
+
+ role = hashtab_search(policydb.p_roles.table, scontextp);
+ if ( !role )
+ goto out_unlock;
+ context.role = role->value;
+
+ /* Extract type. */
+ scontextp = p;
+ while ( *p && *p != ':' )
+ p++;
+ oldc = *p;
+ *p++ = 0;
+
+ typdatum = hashtab_search(policydb.p_types.table, scontextp);
+ if ( !typdatum )
+ goto out_unlock;
+
+ context.type = typdatum->value;
+
+ rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
+ if ( rc )
+ goto out_unlock;
+
+ if ( (p - scontext2) < scontext_len )
+ {
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* Check the validity of the new context. */
+ if ( !policydb_context_isvalid(&policydb, &context) )
+ {
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+ /* Obtain the new sid. */
+ rc = sidtab_context_to_sid(&sidtab, &context, sid);
+out_unlock:
+ POLICY_RDUNLOCK;
+ context_destroy(&context);
+ xfree(scontext2);
+out:
+ return rc;
+}
+
+/**
+ * security_context_to_sid - Obtain a SID for a given security context.
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+{
+ return security_context_to_sid_core(scontext, scontext_len,
+ sid, SECSID_NULL);
+}
+
+/**
+ * security_context_to_sid_default - Obtain a SID for a given security context,
+ * falling back to specified default if needed.
+ *
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ * @def_sid: default SID to assign on errror
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * The default SID is passed to the MLS layer to be used to allow
+ * kernel labeling of the MLS field if the MLS field is not present
+ * (for upgrading to MLS without full relabel).
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+ return security_context_to_sid_core(scontext, scontext_len, sid, def_sid);
+}
+
+static int compute_sid_handle_invalid_context(
+ struct context *scontext, struct context *tcontext, u16 tclass,
+ struct context *newcontext)
+{
+ char *s = NULL, *t = NULL, *n = NULL;
+ u32 slen, tlen, nlen;
+
+ if ( context_struct_to_string(scontext, &s, &slen) < 0 )
+ goto out;
+ if ( context_struct_to_string(tcontext, &t, &tlen) < 0 )
+ goto out;
+ if ( context_struct_to_string(newcontext, &n, &nlen) < 0 )
+ goto out;
+ printk("security_compute_sid: invalid context %s"
+ " for scontext=%s"
+ " tcontext=%s"
+ " tclass=%s",
+ n, s, t, policydb.p_class_val_to_name[tclass-1]);
+out:
+ xfree(s);
+ xfree(t);
+ xfree(n);
+ if ( !flask_enforcing )
+ return 0;
+ return -EACCES;
+}
+
+static int security_compute_sid(u32 ssid,
+ u32 tsid,
+ u16 tclass,
+ u32 specified,
+ u32 *out_sid)
+{
+ struct context *scontext = NULL, *tcontext = NULL, newcontext;
+ struct role_trans *roletr = NULL;
+ struct avtab_key avkey;
+ struct avtab_datum *avdatum;
+ struct avtab_node *node;
+ int rc = 0;
+
+ if ( !ss_initialized )
+ {
+ switch ( tclass )
+ {
+ case SECCLASS_DOMAIN:
+ *out_sid = ssid;
+ break;
+ default:
+ *out_sid = tsid;
+ break;
+ }
+ goto out;
+ }
+
+ POLICY_RDLOCK;
+
+ scontext = sidtab_search(&sidtab, ssid);
+ if ( !scontext )
+ {
+ printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", ssid);
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+ tcontext = sidtab_search(&sidtab, tsid);
+ if ( !tcontext )
+ {
+ printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", tsid);
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+
+ context_init(&newcontext);
+
+ /* Set the user identity. */
+ switch ( specified )
+ {
+ case AVTAB_TRANSITION:
+ case AVTAB_CHANGE:
+ /* Use the process user identity. */
+ newcontext.user = scontext->user;
+ break;
+ case AVTAB_MEMBER:
+ /* Use the related object owner. */
+ newcontext.user = tcontext->user;
+ break;
+ }
+
+ /* Set the role and type to default values. */
+ switch ( tclass )
+ {
+ case SECCLASS_DOMAIN:
+ /* Use the current role and type of process. */
+ newcontext.role = scontext->role;
+ newcontext.type = scontext->type;
+ break;
+ default:
+ /* Use the well-defined object role. */
+ newcontext.role = OBJECT_R_VAL;
+ /* Use the type of the related object. */
+ newcontext.type = tcontext->type;
+ }
+
+ /* Look for a type transition/member/change rule. */
+ avkey.source_type = scontext->type;
+ avkey.target_type = tcontext->type;
+ avkey.target_class = tclass;
+ avkey.specified = specified;
+ avdatum = avtab_search(&policydb.te_avtab, &avkey);
+
+ /* If no permanent rule, also check for enabled conditional rules */
+ if ( !avdatum )
+ {
+ node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
+ for ( ; node != NULL; node = avtab_search_node_next(node, specified) )
+ {
+ if ( node->key.specified & AVTAB_ENABLED )
+ {
+ avdatum = &node->datum;
+ break;
+ }
+ }
+ }
+
+ if ( avdatum )
+ {
+ /* Use the type from the type transition/member/change rule. */
+ newcontext.type = avdatum->data;
+ }
+
+ /* Check for class-specific changes. */
+ switch ( tclass )
+ {
+ case SECCLASS_DOMAIN:
+ if ( specified & AVTAB_TRANSITION )
+ {
+ /* Look for a role transition rule. */
+ for ( roletr = policydb.role_tr; roletr; roletr = roletr->next )
+ {
+ if ( roletr->role == scontext->role &&
+ roletr->type == tcontext->type )
+ {
+ /* Use the role transition rule. */
+ newcontext.role = roletr->new_role;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Set the MLS attributes.
+ This is done last because it may allocate memory. */
+ rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
+ if ( rc )
+ goto out_unlock;
+
+ /* Check the validity of the context. */
+ if ( !policydb_context_isvalid(&policydb, &newcontext) )
+ {
+ rc = compute_sid_handle_invalid_context(scontext, tcontext, tclass,
+ &newcontext);
+ if ( rc )
+ goto out_unlock;
+ }
+ /* Obtain the sid for the context. */
+ rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
+out_unlock:
+ POLICY_RDUNLOCK;
+ context_destroy(&newcontext);
+out:
+ return rc;
+}
+
+/**
+ * security_transition_sid - Compute the SID for a new subject/object.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for new subject/object
+ *
+ * Compute a SID to use for labeling a new subject or object in the
+ * class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the new SID was
+ * computed successfully.
+ */
+int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
+}
+
+/**
+ * security_member_sid - Compute the SID for member selection.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use when selecting a member of a polyinstantiated
+ * object of class @tclass based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_member_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
+}
+
+/**
+ * security_change_sid - Compute the SID for object relabeling.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @out_sid: security identifier for selected member
+ *
+ * Compute a SID to use for relabeling an object of class @tclass
+ * based on a SID pair (@ssid, @tsid).
+ * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
+ * if insufficient memory is available, or %0 if the SID was
+ * computed successfully.
+ */
+int security_change_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+{
+ return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
+}
+
+/*
+ * Verify that each permission that is defined under the
+ * existing policy is still defined with the same value
+ * in the new policy.
+ */
+static int validate_perm(void *key, void *datum, void *p)
+{
+ struct hashtab *h;
+ struct perm_datum *perdatum, *perdatum2;
+ int rc = 0;
+
+ h = p;
+ perdatum = datum;
+
+ perdatum2 = hashtab_search(h, key);
+ if ( !perdatum2 )
+ {
+ printk(KERN_ERR "security: permission %s disappeared", (char *)key);
+ rc = -ENOENT;
+ goto out;
+ }
+ if ( perdatum->value != perdatum2->value )
+ {
+ printk(KERN_ERR "security: the value of permission %s changed",
+ (char *)key);
+ rc = -EINVAL;
+ }
+out:
+ return rc;
+}
+
+/*
+ * Verify that each class that is defined under the
+ * existing policy is still defined with the same
+ * attributes in the new policy.
+ */
+static int validate_class(void *key, void *datum, void *p)
+{
+ struct policydb *newp;
+ struct class_datum *cladatum, *cladatum2;
+ int rc;
+
+ newp = p;
+ cladatum = datum;
+
+ cladatum2 = hashtab_search(newp->p_classes.table, key);
+ if ( !cladatum2 )
+ {
+ printk(KERN_ERR "security: class %s disappeared\n", (char *)key);
+ rc = -ENOENT;
+ goto out;
+ }
+ if (cladatum->value != cladatum2->value) {
+ printk(KERN_ERR "security: the value of class %s changed\n",
+ (char *)key);
+ rc = -EINVAL;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog