aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsmh22@firebug.cl.cam.ac.uk <smh22@firebug.cl.cam.ac.uk>2005-06-20 22:28:08 +0000
committersmh22@firebug.cl.cam.ac.uk <smh22@firebug.cl.cam.ac.uk>2005-06-20 22:28:08 +0000
commit80070b4a6ca1205c8bc00926fa23c997797f053c (patch)
tree0b9e314460f38c8989c228e5344a570f187e148a
parent6b76d296bbfad35e3cea2f6073820e1dc9d8a8e7 (diff)
downloadxen-80070b4a6ca1205c8bc00926fa23c997797f053c.tar.gz
xen-80070b4a6ca1205c8bc00926fa23c997797f053c.tar.bz2
xen-80070b4a6ca1205c8bc00926fa23c997797f053c.zip
bitkeeper revision 1.1718.1.7 (42b742f8NxTuN2pqCHFAWI78dbEYKw)
Initial MAC (sHype) support from IBM. Defaults to NULL policy for now. Signed-off-by: Reiner Sailer <sailer@us.ibm.com> Signed-off-by: Stefan Berger <stefanb@us.ibm.com> Signed-off-by: Steven Hand <steven@xensource.com>
-rw-r--r--.rootkeys15
-rw-r--r--tools/Makefile1
-rw-r--r--tools/libxc/xc.h2
-rw-r--r--tools/libxc/xc_domain.c3
-rw-r--r--tools/policy/Makefile36
-rw-r--r--tools/policy/policy_tool.c557
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c10
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py16
-rw-r--r--tools/python/xen/xend/image.py6
-rw-r--r--tools/python/xen/xend/server/SrvDomainDir.py1
-rw-r--r--tools/python/xen/xm/create.py7
-rw-r--r--tools/python/xen/xm/main.py10
-rw-r--r--tools/python/xen/xm/opts.py7
-rw-r--r--xen/Makefile4
-rw-r--r--xen/Rules.mk1
-rw-r--r--xen/acm/Makefile15
-rw-r--r--xen/acm/acm_chinesewall_hooks.c503
-rw-r--r--xen/acm/acm_core.c205
-rw-r--r--xen/acm/acm_null_hooks.c76
-rw-r--r--xen/acm/acm_policy.c197
-rw-r--r--xen/acm/acm_simple_type_enforcement_hooks.c638
-rw-r--r--xen/arch/x86/setup.c6
-rw-r--r--xen/arch/x86/x86_32/entry.S1
-rw-r--r--xen/common/dom0_ops.c15
-rw-r--r--xen/common/event_channel.c4
-rw-r--r--xen/common/grant_table.c6
-rw-r--r--xen/common/policy_ops.c117
-rw-r--r--xen/include/acm/acm_core.h117
-rw-r--r--xen/include/acm/acm_endian.h88
-rw-r--r--xen/include/acm/acm_hooks.h337
-rw-r--r--xen/include/public/acm.h161
-rw-r--r--xen/include/public/acm_dom0_setup.h34
-rw-r--r--xen/include/public/dom0_ops.h3
-rw-r--r--xen/include/public/policy_ops.h74
-rw-r--r--xen/include/public/xen.h1
-rw-r--r--xen/include/xen/sched.h2
36 files changed, 3259 insertions, 17 deletions
diff --git a/.rootkeys b/.rootkeys
index 338b1be862..b04c5ff74b 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -785,6 +785,8 @@
41adc641dV-0cDLSyzMs5BT8nL7v3Q tools/misc/xenperf.c
4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
+42b742f6JFcp6LFpYu-B4AEsfQwSFw tools/policy/Makefile
+42b742f66XOdRMrwaHvbCdSSQyCrFw tools/policy/policy_tool.c
4270cc81g3nSNYCZ1ryCMDEbLtMtbQ tools/pygrub/Makefile
4270deeccyRsJn6jLnRh9odRtMW9SA tools/pygrub/README
4270cc81EIl7NyaS3Av6IPRk2c2a6Q tools/pygrub/setup.py
@@ -1101,6 +1103,12 @@
3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
+42b742f6XHTfIEm_hUPtzjKr37LVhw xen/acm/Makefile
+42b742f6tHzn0fZWH3TjPva8gbqpow xen/acm/acm_chinesewall_hooks.c
+42b742f6bM8kZwuIUbepHZ8SQQkjJA xen/acm/acm_core.c
+42b742f6cwfrPubqH47gQpke8xkYSA xen/acm/acm_null_hooks.c
+42b742f69qSxm5MM-wtPaWtCqyI3KA xen/acm/acm_policy.c
+42b742f6VbmdlwekQRMhXugjcu9QXg xen/acm/acm_simple_type_enforcement_hooks.c
421098b25A0RvuYN3rP28ga3_FN3_Q xen/arch/ia64/Makefile
421098b2okIeYXS9w9avmSozls61xA xen/arch/ia64/Rules.mk
421098b21p12UcKjHBrLh_LjlvNEwA xen/arch/ia64/acpi.c
@@ -1324,6 +1332,7 @@
41a61536SZbR6cj1ukWTb0DYU-vz9w xen/common/multicall.c
3ddb79bdD4SLmmdMD7yLW5HcUWucXw xen/common/page_alloc.c
3e54c38dkHAev597bPr71-hGzTdocg xen/common/perfc.c
+42b742f6mgq9puEr7lUrLST0VEpsig xen/common/policy_ops.c
40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c
41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c
3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
@@ -1339,6 +1348,9 @@
4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c
4298e018XQtZkCdufpyFimOGZqqsFA xen/drivers/char/ns16550.c
3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c
+42b742f6OteAMPWnoqxqfRX3yxD0yw xen/include/acm/acm_core.h
+42b742f6XfIijctEwA0YWL2BoWtDNg xen/include/acm/acm_endian.h
+42b742f6jXvp1vdbU2v2WJjTPku65A xen/include/acm/acm_hooks.h
40715b2cFpte_UNWnBZW0Du7z9AhTQ xen/include/acpi/acconfig.h
40715b2ctNvVZ058w8eM8DR9hOat_A xen/include/acpi/acexcep.h
40715b2com8I01qcHcAw47e93XsCqQ xen/include/acpi/acglobal.h
@@ -1489,6 +1501,8 @@
404f1bc4tWkB9Qr8RkKtZGW5eMQzhw xen/include/asm-x86/x86_64/uaccess.h
422f27c8RHFkePhD34VIEpMMqofZcA xen/include/asm-x86/x86_emulate.h
400304fcmRQmDdFYEzDh0wcBba9alg xen/include/public/COPYING
+42b742f6duiOTlZvysQkRYZHYBXqvg xen/include/public/acm.h
+42b742f7TIMsQgUaNDJXp3QlBve2SQ xen/include/public/acm_dom0_setup.h
421098b7OKb9YH_EUA_UpCxBjaqtgA xen/include/public/arch-ia64.h
404f1bc68SXxmv0zQpXBWGrCzSyp8w xen/include/public/arch-x86_32.h
404f1bc7IwU-qnH8mJeVu0YsNGMrcw xen/include/public/arch-x86_64.h
@@ -1502,6 +1516,7 @@
41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
41ee5e8c6mLxIx82KPsbpt_uts_vSA xen/include/public/io/usbif.h
4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
+42b742f7Lzy8SKKG25L_-fgk5FHA2Q xen/include/public/policy_ops.h
40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
42b5a5f2QC1IxeuwCwwsOEhvcJ2BJg xen/include/public/version.h
diff --git a/tools/Makefile b/tools/Makefile
index 3a38e899de..00eb4991cc 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,6 +12,7 @@ SUBDIRS += xcs
SUBDIRS += xcutils
SUBDIRS += pygrub
SUBDIRS += firmware
+SUBDIRS += policy
.PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h
index 27e7845798..e54f9b198d 100644
--- a/tools/libxc/xc.h
+++ b/tools/libxc/xc.h
@@ -110,6 +110,7 @@ int xc_waitdomain_core(int domain,
typedef struct {
u32 domid;
+ u32 ssidref;
unsigned int dying:1, crashed:1, shutdown:1,
paused:1, blocked:1, running:1;
unsigned int shutdown_reason; /* only meaningful if shutdown==1 */
@@ -124,6 +125,7 @@ typedef struct {
typedef dom0_getdomaininfo_t xc_domaininfo_t;
int xc_domain_create(int xc_handle,
+ u32 ssidref,
u32 *pdomid);
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 8f0bba3216..2edf11c39d 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -9,6 +9,7 @@
#include "xc_private.h"
int xc_domain_create(int xc_handle,
+ u32 ssidref,
u32 *pdomid)
{
int err;
@@ -16,6 +17,7 @@ int xc_domain_create(int xc_handle,
op.cmd = DOM0_CREATEDOMAIN;
op.u.createdomain.domain = (domid_t)*pdomid;
+ op.u.createdomain.ssidref = ssidref;
if ( (err = do_dom0_op(xc_handle, &op)) != 0 )
return err;
@@ -101,6 +103,7 @@ int xc_domain_getinfo(int xc_handle,
info->crashed = 1;
}
+ info->ssidref = op.u.getdomaininfo.ssidref;
info->nr_pages = op.u.getdomaininfo.tot_pages;
info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT);
info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
diff --git a/tools/policy/Makefile b/tools/policy/Makefile
new file mode 100644
index 0000000000..b8d67471ae
--- /dev/null
+++ b/tools/policy/Makefile
@@ -0,0 +1,36 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SRCS = policy_tool.c
+CFLAGS += -static
+CFLAGS += -Wall
+CFLAGS += -Werror
+CFLAGS += -O3
+CFLAGS += -fno-strict-aliasing
+CFLAGS += -I.
+
+all: build
+build: mk-symlinks
+ $(MAKE) policy_tool
+
+default: all
+
+install: all
+
+policy_tool : policy_tool.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
+
+clean:
+ rm -rf policy_tool xen
+
+
+LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
+mk-symlinks:
+ [ -e xen/linux ] || mkdir -p xen/linux
+ [ -e xen/io ] || mkdir -p xen/io
+ ( cd xen >/dev/null ; \
+ ln -sf ../$(XEN_ROOT)/xen/include/public/*.h . )
+ ( cd xen/io >/dev/null ; \
+ ln -sf ../../$(XEN_ROOT)/xen/include/public/io/*.h . )
+ ( cd xen/linux >/dev/null ; \
+ ln -sf ../../$(LINUX_ROOT)/include/asm-xen/linux-public/*.h . )
diff --git a/tools/policy/policy_tool.c b/tools/policy/policy_tool.c
new file mode 100644
index 0000000000..696a70c282
--- /dev/null
+++ b/tools/policy/policy_tool.c
@@ -0,0 +1,557 @@
+/****************************************************************
+ * policy_tool.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Stefan Berger <stefanb@watson.ibm.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 of the
+ * License.
+ *
+ * sHype policy management tool. This code runs in a domain and
+ * manages the Xen security policy by interacting with the
+ * Xen access control module via a /proc/xen/policycmd proc-ioctl,
+ * which is translated into a policy_op hypercall into Xen.
+ *
+ * todo: implement setpolicy to dynamically set a policy cache.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int8_t s8;
+typedef int16_t s16;
+typedef int32_t s32;
+typedef int64_t s64;
+
+#include <xen/acm.h>
+
+#include <xen/policy_ops.h>
+
+#include <xen/linux/privcmd.h>
+
+#define ERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m "\n" , ## _a )
+
+#define PERROR(_m, _a...) \
+ fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
+ errno, strerror(errno))
+
+static inline int do_policycmd(int xc_handle,
+ unsigned int cmd,
+ unsigned long data)
+{
+ return ioctl(xc_handle, cmd, data);
+}
+
+static inline int do_xen_hypercall(int xc_handle,
+ privcmd_hypercall_t *hypercall)
+{
+ return do_policycmd(xc_handle,
+ IOCTL_PRIVCMD_HYPERCALL,
+ (unsigned long)hypercall);
+}
+
+static inline int do_policy_op(int xc_handle, policy_op_t *op)
+{
+ int ret = -1;
+ privcmd_hypercall_t hypercall;
+
+ op->interface_version = POLICY_INTERFACE_VERSION;
+
+ hypercall.op = __HYPERVISOR_policy_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen policy hypercall");
+ goto out1;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "POLICY operation failed -- need to"
+ " rebuild the user-space tool set?\n");
+ goto out2;
+ }
+
+ out2: (void)munlock(op, sizeof(*op));
+ out1: return ret;
+}
+
+/*************************** DUMPS *******************************/
+
+void acm_dump_chinesewall_buffer(void *buf, int buflen) {
+
+ struct acm_chwall_policy_buffer *cwbuf = (struct acm_chwall_policy_buffer *)buf;
+ domaintype_t *ssids, *conflicts, *running_types, *conflict_aggregate;
+ int i,j;
+
+
+ if (htons(cwbuf->policy_code) != ACM_CHINESE_WALL_POLICY) {
+ printf("CHINESE WALL POLICY CODE not found ERROR!!\n");
+ return;
+ }
+ printf("\n\nChinese Wall policy:\n");
+ printf("====================\n");
+ printf("Max Types = %x.\n", ntohs(cwbuf->chwall_max_types));
+ printf("Max Ssidrefs = %x.\n", ntohs(cwbuf->chwall_max_ssidrefs));
+ printf("Max ConfSets = %x.\n", ntohs(cwbuf->chwall_max_conflictsets));
+ printf("Ssidrefs Off = %x.\n", ntohs(cwbuf->chwall_ssid_offset));
+ printf("Conflicts Off = %x.\n", ntohs(cwbuf->chwall_conflict_sets_offset));
+ printf("Runing T. Off = %x.\n", ntohs(cwbuf->chwall_running_types_offset));
+ printf("C. Agg. Off = %x.\n", ntohs(cwbuf->chwall_conflict_aggregate_offset));
+ printf("\nSSID To CHWALL-Type matrix:\n");
+
+ ssids = (domaintype_t *)(buf + ntohs(cwbuf->chwall_ssid_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_ssidrefs); i++) {
+ printf("\n ssidref%2x: ", i);
+ for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+ printf("%02x ", ntohs(ssids[i*ntohs(cwbuf->chwall_max_types) + j]));
+ }
+ printf("\n\nConfict Sets:\n");
+ conflicts = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_sets_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_conflictsets); i++) {
+ printf("\n c-set%2x: ", i);
+ for(j=0; j< ntohs(cwbuf->chwall_max_types); j++)
+ printf("%02x ", ntohs(conflicts[i*ntohs(cwbuf->chwall_max_types) +j]));
+ }
+ printf("\n");
+
+ printf("\nRunning\nTypes: ");
+ if (ntohs(cwbuf->chwall_running_types_offset)) {
+ running_types = (domaintype_t *)(buf + ntohs(cwbuf->chwall_running_types_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+ printf("%02x ", ntohs(running_types[i]));
+ }
+ printf("\n");
+ } else {
+ printf("Not Reported!\n");
+ }
+ printf("\nConflict\nAggregate Set: ");
+ if (ntohs(cwbuf->chwall_conflict_aggregate_offset)) {
+ conflict_aggregate = (domaintype_t *)(buf + ntohs(cwbuf->chwall_conflict_aggregate_offset));
+ for(i=0; i< ntohs(cwbuf->chwall_max_types); i++) {
+ printf("%02x ", ntohs(conflict_aggregate[i]));
+ }
+ printf("\n\n");
+ } else {
+ printf("Not Reported!\n");
+ }
+}
+
+void acm_dump_ste_buffer(void *buf, int buflen) {
+
+ struct acm_ste_policy_buffer *stebuf = (struct acm_ste_policy_buffer *)buf;
+ domaintype_t *ssids;
+ int i,j;
+
+
+ if (ntohs(stebuf->policy_code) != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ printf("SIMPLE TYPE ENFORCEMENT POLICY CODE not found ERROR!!\n");
+ return;
+ }
+ printf("\nSimple Type Enforcement policy:\n");
+ printf("===============================\n");
+ printf("Max Types = %x.\n", ntohs(stebuf->ste_max_types));
+ printf("Max Ssidrefs = %x.\n", ntohs(stebuf->ste_max_ssidrefs));
+ printf("Ssidrefs Off = %x.\n", ntohs(stebuf->ste_ssid_offset));
+ printf("\nSSID To STE-Type matrix:\n");
+
+ ssids = (domaintype_t *)(buf + ntohs(stebuf->ste_ssid_offset));
+ for(i=0; i< ntohs(stebuf->ste_max_ssidrefs); i++) {
+ printf("\n ssidref%2x: ", i);
+ for(j=0; j< ntohs(stebuf->ste_max_types); j++)
+ printf("%02x ", ntohs(ssids[i*ntohs(stebuf->ste_max_types) +j]));
+ }
+ printf("\n\n");
+}
+
+void acm_dump_policy_buffer(void *buf, int buflen) {
+ struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
+
+ printf("\nPolicy dump:\n");
+ printf("============\n");
+ printf("Magic = %x.\n", ntohl(pol->magic));
+ printf("PolVer = %x.\n", ntohl(pol->policyversion));
+ printf("Len = %x.\n", ntohl(pol->len));
+ printf("Primary = %s (c=%x, off=%x).\n",
+ ACM_POLICY_NAME(ntohs(pol->primary_policy_code)),
+ ntohs(pol->primary_policy_code), ntohs(pol->primary_buffer_offset));
+ printf("Secondary = %s (c=%x, off=%x).\n",
+ ACM_POLICY_NAME(ntohs(pol->secondary_policy_code)),
+ ntohs(pol->secondary_policy_code), ntohs(pol->secondary_buffer_offset));
+ switch (ntohs(pol->primary_policy_code)) {
+ case ACM_CHINESE_WALL_POLICY:
+ acm_dump_chinesewall_buffer(buf+ntohs(pol->primary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ acm_dump_ste_buffer(buf+ntohs(pol->primary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->primary_buffer_offset));
+ break;
+ case ACM_NULL_POLICY:
+ printf("Primary policy is NULL Policy (n/a).\n");
+ break;
+ default:
+ printf("UNKNOWN POLICY!\n");
+ }
+ switch (ntohs(pol->secondary_policy_code)) {
+ case ACM_CHINESE_WALL_POLICY:
+ acm_dump_chinesewall_buffer(buf+ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ acm_dump_ste_buffer(buf+ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) - ntohs(pol->secondary_buffer_offset));
+ break;
+ case ACM_NULL_POLICY:
+ printf("Secondary policy is NULL Policy (n/a).\n");
+ break;
+ default:
+ printf("UNKNOWN POLICY!\n");
+ }
+ printf("\nPolicy dump End.\n\n");
+}
+
+/*************************** set policy ****************************/
+
+int acm_domain_set_chwallpolicy(void *bufstart, int buflen) {
+#define CWALL_MAX_SSIDREFS 5
+#define CWALL_MAX_TYPES 10
+#define CWALL_MAX_CONFLICTSETS 2
+
+ struct acm_chwall_policy_buffer *chwall_bin_pol = (struct acm_chwall_policy_buffer *)bufstart;
+ domaintype_t *ssidrefs, *conflicts;
+ int ret = 0;
+ int i,j;
+
+ chwall_bin_pol->chwall_max_types = htons(CWALL_MAX_TYPES);
+ chwall_bin_pol->chwall_max_ssidrefs = htons(CWALL_MAX_SSIDREFS);
+ chwall_bin_pol->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ chwall_bin_pol->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+ chwall_bin_pol->chwall_max_conflictsets = htons(CWALL_MAX_CONFLICTSETS);
+ chwall_bin_pol->chwall_conflict_sets_offset =
+ htons(
+ ntohs(chwall_bin_pol->chwall_ssid_offset) +
+ sizeof(domaintype_t)*CWALL_MAX_SSIDREFS*CWALL_MAX_TYPES);
+ chwall_bin_pol->chwall_running_types_offset = 0; /* not set */
+ chwall_bin_pol->chwall_conflict_aggregate_offset = 0; /* not set */
+ ret += sizeof(struct acm_chwall_policy_buffer);
+ /* now push example ssids into the buffer (max_ssidrefs x max_types entries) */
+ /* check buffer size */
+ if ((buflen - ret) < (CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ ssidrefs = (domaintype_t *)(bufstart+ntohs(chwall_bin_pol->chwall_ssid_offset));
+ for(i=0; i< CWALL_MAX_SSIDREFS; i++) {
+ for (j=0; j< CWALL_MAX_TYPES; j++)
+ ssidrefs[i*CWALL_MAX_TYPES + j] = htons(0);
+ /* here, set type i for ssidref i; generally, a ssidref can have multiple chwall types */
+ if (i < CWALL_MAX_SSIDREFS)
+ ssidrefs[i*CWALL_MAX_TYPES + i] = htons(1);
+ }
+ ret += CWALL_MAX_TYPES*CWALL_MAX_SSIDREFS*sizeof(domaintype_t);
+ if ((buflen - ret) < (CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ /* now the chinese wall policy conflict sets*/
+ conflicts = (domaintype_t *)(bufstart +
+ ntohs(chwall_bin_pol->chwall_conflict_sets_offset));
+ memset((void *)conflicts, 0, CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES*sizeof(domaintype_t));
+ /* just 1 conflict set [0]={2,3}, [1]={0,5,6} */
+ if (CWALL_MAX_TYPES > 3) {
+ conflicts[2] = htons(1); conflicts[3] = htons(1); /* {2,3} */
+ conflicts[CWALL_MAX_TYPES] = htons(1); conflicts[CWALL_MAX_TYPES+5] = htons(1);
+ conflicts[CWALL_MAX_TYPES+6] = htons(1);/* {0,5,6} */
+ }
+ ret += sizeof(domaintype_t)*CWALL_MAX_CONFLICTSETS*CWALL_MAX_TYPES;
+ return ret;
+}
+
+int acm_domain_set_stepolicy(void *bufstart, int buflen) {
+#define STE_MAX_SSIDREFS 5
+#define STE_MAX_TYPES 5
+
+ struct acm_ste_policy_buffer *ste_bin_pol = (struct acm_ste_policy_buffer *)bufstart;
+ domaintype_t *ssidrefs;
+ int i,j, ret = 0;
+
+ ste_bin_pol->ste_max_types = htons(STE_MAX_TYPES);
+ ste_bin_pol->ste_max_ssidrefs = htons(STE_MAX_SSIDREFS);
+ ste_bin_pol->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+ ste_bin_pol->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+ ret += sizeof(struct acm_ste_policy_buffer);
+ /* check buffer size */
+ if ((buflen - ret) < (STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t)))
+ return -1; /* not enough space */
+
+ ssidrefs = (domaintype_t *)(bufstart+ntohs(ste_bin_pol->ste_ssid_offset));
+ for(i=0; i< STE_MAX_SSIDREFS; i++) {
+ for (j=0; j< STE_MAX_TYPES; j++)
+ ssidrefs[i*STE_MAX_TYPES + j] = htons(0);
+ /* set type i in ssidref 0 and ssidref i */
+ ssidrefs[i] = htons(1); /* ssidref 0 has all types set */
+ if (i < STE_MAX_SSIDREFS)
+ ssidrefs[i*STE_MAX_TYPES + i] = htons(1);
+ }
+ ret += STE_MAX_TYPES*STE_MAX_SSIDREFS*sizeof(domaintype_t);
+ return ret;
+}
+
+#define MAX_PUSH_BUFFER 16384
+u8 push_buffer[MAX_PUSH_BUFFER];
+
+int acm_domain_setpolicy(int xc_handle)
+{
+ int ret;
+ struct acm_policy_buffer *bin_pol;
+ policy_op_t op;
+
+ /* future: read policy from file and set it */
+ bin_pol = (struct acm_policy_buffer *)push_buffer;
+ bin_pol->magic = htonl(ACM_MAGIC);
+ bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+ bin_pol->primary_policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ bin_pol->secondary_policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+
+ bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+ bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+ ret = acm_domain_set_chwallpolicy(push_buffer + ntohs(bin_pol->primary_buffer_offset),
+ MAX_PUSH_BUFFER - ntohs(bin_pol->primary_buffer_offset));
+ if (ret < 0) {
+ printf("ERROR creating chwallpolicy buffer.\n");
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+ ret = acm_domain_set_stepolicy(push_buffer + ntohs(bin_pol->secondary_buffer_offset),
+ MAX_PUSH_BUFFER - ntohs(bin_pol->secondary_buffer_offset));
+ if (ret < 0) {
+ printf("ERROR creating chwallpolicy buffer.\n");
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+
+ /* dump it and then push it down into xen/acm */
+ acm_dump_policy_buffer(push_buffer, ntohl(bin_pol->len));
+ op.cmd = POLICY_SETPOLICY;
+ op.u.setpolicy.pushcache = (void *)push_buffer;
+ op.u.setpolicy.pushcache_size = ntohl(bin_pol->len);
+ op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret)
+ printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+ else
+ printf("Successfully changed policy.\n");
+ return ret;
+}
+
+/******************************* get policy ******************************/
+
+#define PULL_CACHE_SIZE 8192
+u8 pull_buffer[PULL_CACHE_SIZE];
+int acm_domain_getpolicy(int xc_handle)
+{
+ policy_op_t op;
+ int ret;
+
+ memset(pull_buffer, 0x00, sizeof(pull_buffer));
+ op.cmd = POLICY_GETPOLICY;
+ op.u.getpolicy.pullcache = (void *)pull_buffer;
+ op.u.getpolicy.pullcache_size = sizeof(pull_buffer);
+ ret = do_policy_op(xc_handle, &op);
+ /* dump policy */
+ acm_dump_policy_buffer(pull_buffer, sizeof(pull_buffer));
+ return ret;
+}
+
+/************************ load binary policy ******************************/
+
+int acm_domain_loadpolicy(int xc_handle,
+ const char *filename)
+{
+ struct stat mystat;
+ int ret, fd;
+ off_t len;
+ u8 *buffer;
+
+ if ((ret = stat(filename, &mystat))) {
+ printf("File %s not found.\n",filename);
+ goto out;
+ }
+
+ len = mystat.st_size;
+ if ((buffer = malloc(len)) == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if ((fd = open(filename, O_RDONLY)) <= 0) {
+ ret = -ENOENT;
+ printf("File %s not found.\n",filename);
+ goto free_out;
+ }
+ if (len == read(fd, buffer, len)) {
+ policy_op_t op;
+ /* dump it and then push it down into xen/acm */
+ acm_dump_policy_buffer(buffer, len);
+ op.cmd = POLICY_SETPOLICY;
+ op.u.setpolicy.pushcache = (void *)buffer;
+ op.u.setpolicy.pushcache_size = len;
+ op.u.setpolicy.policy_type = ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret)
+ printf("ERROR setting policy. Use 'xm dmesg' to see details.\n");
+ else
+ printf("Successfully changed policy.\n");
+
+ } else {
+ ret = -1;
+ }
+ close(fd);
+ free_out:
+ free(buffer);
+ out:
+ return ret;
+}
+
+/************************ dump hook statistics ******************************/
+void
+dump_ste_stats(struct acm_ste_stats_buffer *ste_stats)
+{
+ printf("STE-Policy Security Hook Statistics:\n");
+ printf("ste: event_channel eval_count = %d\n", ntohl(ste_stats->ec_eval_count));
+ printf("ste: event_channel denied_count = %d\n", ntohl(ste_stats->ec_denied_count));
+ printf("ste: event_channel cache_hit_count = %d\n", ntohl(ste_stats->ec_cachehit_count));
+ printf("ste:\n");
+ printf("ste: grant_table eval_count = %d\n", ntohl(ste_stats->gt_eval_count));
+ printf("ste: grant_table denied_count = %d\n", ntohl(ste_stats->gt_denied_count));
+ printf("ste: grant_table cache_hit_count = %d\n", ntohl(ste_stats->gt_cachehit_count));
+}
+
+#define PULL_STATS_SIZE 8192
+int acm_domain_dumpstats(int xc_handle)
+{
+ u8 stats_buffer[PULL_STATS_SIZE];
+ policy_op_t op;
+ int ret;
+ struct acm_stats_buffer *stats;
+
+ memset(stats_buffer, 0x00, sizeof(stats_buffer));
+ op.cmd = POLICY_DUMPSTATS;
+ op.u.dumpstats.pullcache = (void *)stats_buffer;
+ op.u.dumpstats.pullcache_size = sizeof(stats_buffer);
+ ret = do_policy_op(xc_handle, &op);
+
+ if (ret < 0) {
+ printf("ERROR dumping policy stats. Use 'xm dmesg' to see details.\n");
+ return ret;
+ }
+ stats = (struct acm_stats_buffer *)stats_buffer;
+
+ printf("\nPolicy dump:\n");
+ printf("============\n");
+ printf("Magic = %x.\n", ntohl(stats->magic));
+ printf("PolVer = %x.\n", ntohl(stats->policyversion));
+ printf("Len = %x.\n", ntohl(stats->len));
+
+ switch(ntohs(stats->primary_policy_code)) {
+ case ACM_NULL_POLICY:
+ printf("NULL Policy: No statistics apply.\n");
+ break;
+ case ACM_CHINESE_WALL_POLICY:
+ printf("Chinese Wall Policy: No statistics apply.\n");
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->primary_stats_offset)));
+ break;
+ default:
+ printf("UNKNOWN PRIMARY POLICY ERROR!\n");
+ }
+ switch(ntohs(stats->secondary_policy_code)) {
+ case ACM_NULL_POLICY:
+ printf("NULL Policy: No statistics apply.\n");
+ break;
+ case ACM_CHINESE_WALL_POLICY:
+ printf("Chinese Wall Policy: No statistics apply.\n");
+ break;
+ case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
+ dump_ste_stats((struct acm_ste_stats_buffer *)(stats_buffer + ntohs(stats->secondary_stats_offset)));
+ break;
+ default:
+ printf("UNKNOWN SECONDARY POLICY ERROR!\n");
+ }
+ return ret;
+}
+
+/***************************** main **************************************/
+
+void
+usage(char *progname){
+ printf("Use: %s \n"
+ "\t setpolicy\n"
+ "\t getpolicy\n"
+ "\t dumpstats\n"
+ "\t loadpolicy <binary policy file>\n", progname);
+ exit(-1);
+}
+
+int
+main(int argc, char **argv) {
+
+ int policycmd_fd;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ if ((policycmd_fd = open("/proc/xen/privcmd", O_RDONLY)) <= 0) {
+ printf("ERROR: Could not open xen policycmd device!\n");
+ exit(-1);
+ }
+
+ if (!strcmp(argv[1], "setpolicy")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_setpolicy(policycmd_fd);
+
+ } else if (!strcmp(argv[1], "getpolicy")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_getpolicy(policycmd_fd);
+
+ } else if (!strcmp(argv[1], "loadpolicy")) {
+ if (argc != 3)
+ usage(argv[0]);
+ acm_domain_loadpolicy(policycmd_fd, argv[2]);
+
+ } else if (!strcmp(argv[1], "dumpstats")) {
+ if (argc != 2)
+ usage(argv[0]);
+ acm_domain_dumpstats(policycmd_fd);
+
+ } else
+ usage(argv[0]);
+
+ close(policycmd_fd);
+ return 0;
+}
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 13d60be08e..81721d961e 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -78,13 +78,14 @@ static PyObject *pyxc_domain_create(PyObject *self,
u32 dom = 0;
int ret;
+ u32 ssidref = 0xFFFFFFFF;
- static char *kwd_list[] = { "dom", NULL };
+ static char *kwd_list[] = { "dom", "ssidref", NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwd_list, &dom))
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list, &dom, &ssidref))
return NULL;
- if ( (ret = xc_domain_create(xc->xc_handle, &dom)) < 0 )
+ if ( (ret = xc_domain_create(xc->xc_handle, ssidref, &dom)) < 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(dom);
@@ -230,7 +231,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
}
info_dict = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i"
- ",s:l,s:L,s:l,s:i}",
+ ",s:l,s:L,s:l,s:i,s:i}",
"dom", info[i].domid,
"vcpus", info[i].vcpus,
"dying", info[i].dying,
@@ -242,6 +243,7 @@ static PyObject *pyxc_domain_getinfo(PyObject *self,
"mem_kb", info[i].nr_pages*4,
"cpu_time", info[i].cpu_time,
"maxmem_kb", info[i].max_memkb,
+ "ssidref", info[i].ssidref,
"shutdown_reason", info[i].shutdown_reason);
PyDict_SetItemString( info_dict, "vcpu_to_cpu", vcpu_list );
PyDict_SetItemString( info_dict, "cpumap", cpumap_list );
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index a47709a369..0383b9c981 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -202,7 +202,9 @@ class XendDomainInfo:
"""
db = parentdb.addChild(uuid)
vm = cls(db)
- id = xc.domain_create()
+ ssidref = int(sxp.child_value(config, 'ssidref'))
+ log.debug('restoring with ssidref='+str(ssidref))
+ id = xc.domain_create(ssidref = ssidref)
vm.setdom(id)
try:
vm.restore = True
@@ -241,6 +243,7 @@ class XendDomainInfo:
self.start_time = None
self.name = None
self.memory = None
+ self.ssidref = None
self.image = None
self.channel = None
@@ -316,6 +319,7 @@ class XendDomainInfo:
"""
self.info = info
self.memory = self.info['mem_kb'] / 1024
+ self.ssidref = self.info['ssidref']
def state_set(self, state):
self.state_updated.acquire()
@@ -336,6 +340,7 @@ class XendDomainInfo:
s += " id=" + str(self.id)
s += " name=" + self.name
s += " memory=" + str(self.memory)
+ s += " ssidref=" + str(self.ssidref)
console = self.getConsole()
if console:
s += " console=" + str(console.console_port)
@@ -398,7 +403,8 @@ class XendDomainInfo:
sxpr = ['domain',
['id', self.id],
['name', self.name],
- ['memory', self.memory] ]
+ ['memory', self.memory],
+ ['ssidref', self.ssidref] ]
if self.uuid:
sxpr.append(['uuid', self.uuid])
if self.info:
@@ -533,6 +539,7 @@ class XendDomainInfo:
self.memory = int(sxp.child_value(config, 'memory'))
if self.memory is None:
raise VmError('missing memory size')
+ self.ssidref = int(sxp.child_value(config, 'ssidref'))
cpu = sxp.child_value(config, 'cpu')
if self.recreate and self.id and cpu is not None and int(cpu) >= 0:
xc.domain_pincpu(self.id, 0, 1<<int(cpu))
@@ -644,7 +651,7 @@ class XendDomainInfo:
def show(self):
"""Print virtual machine info.
"""
- print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory)
+ print "[VM dom=%d name=%s memory=%d ssidref=%d" % (self.id, self.name, self.memory, self.ssidref)
print "image:"
sxp.show(self.image)
print "]"
@@ -660,7 +667,7 @@ class XendDomainInfo:
cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
except:
raise VmError('invalid cpu')
- id = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight)
+ id = self.image.initDomain(self.id, self.memory, self.ssidref, cpu, self.cpu_weight)
log.debug('init_domain> Created domain=%d name=%s memory=%d',
id, self.name, self.memory)
self.setdom(id)
@@ -1011,6 +1018,7 @@ addImageHandlerClass(VmxImageHandler)
# Ignore the fields we already handle.
add_config_handler('name', vm_field_ignore)
add_config_handler('memory', vm_field_ignore)
+add_config_handler('ssidref', vm_field_ignore)
add_config_handler('cpu', vm_field_ignore)
add_config_handler('cpu_weight', vm_field_ignore)
add_config_handler('console', vm_field_ignore)
diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py
index f3b8642a5f..5abc121e86 100644
--- a/tools/python/xen/xend/image.py
+++ b/tools/python/xen/xend/image.py
@@ -111,7 +111,7 @@ class ImageHandler:
except OSError, ex:
log.warning("error removing bootloader file '%s': %s", f, ex)
- def initDomain(self, dom, memory, cpu, cpu_weight):
+ def initDomain(self, dom, memory, ssidref, cpu, cpu_weight):
"""Initial domain create.
@return domain id
@@ -119,14 +119,14 @@ class ImageHandler:
mem_kb = self.getDomainMemory(memory)
if not self.vm.restore:
- dom = xc.domain_create(dom = dom or 0)
+ dom = xc.domain_create(dom = dom or 0, ssidref = ssidref)
# if bootloader, unlink here. But should go after buildDomain() ?
if self.vm.bootloader:
self.unlink(self.kernel)
self.unlink(self.ramdisk)
if dom <= 0:
raise VmError('Creating domain failed: name=%s' % self.vm.name)
- log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom)
+ log.debug("initDomain: cpu=%d mem_kb=%d ssidref=%d dom=%d", cpu, mem_kb, ssidref, dom)
# xc.domain_setuuid(dom, uuid)
xc.domain_setcpuweight(dom, cpu_weight)
xc.domain_setmaxmem(dom, mem_kb)
diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py
index d6f6291716..7fcc7c5cf7 100644
--- a/tools/python/xen/xend/server/SrvDomainDir.py
+++ b/tools/python/xen/xend/server/SrvDomainDir.py
@@ -142,6 +142,7 @@ class SrvDomainDir(SrvDir):
% (url, d.name, d.name))
req.write('id=%s' % d.id)
req.write('memory=%d'% d.memory)
+ req.write('ssidref=%d'% d.ssidref)
req.write('</li>')
req.write('</ul>')
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 23001cc458..d2219f9668 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -120,6 +120,10 @@ gopts.var('memory', val='MEMORY',
fn=set_int, default=128,
use="Domain memory in MB.")
+gopts.var('ssidref', val='SSIDREF',
+ fn=set_u32, default=0xffffffff,
+ use="Security Identifier.")
+
gopts.var('maxmem', val='MEMORY',
fn=set_int, default=None,
use="Maximum domain memory in MB.")
@@ -405,7 +409,8 @@ def make_config(opts, vals):
config = ['vm',
['name', vals.name ],
- ['memory', vals.memory ]]
+ ['memory', vals.memory ],
+ ['ssidref', vals.ssidref ]]
if vals.maxmem:
config.append(['maxmem', vals.maxmem])
if vals.cpu is not None:
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index d02a190ac4..6eda17e2a9 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -383,7 +383,7 @@ class ProgList(Prog):
self.brief_list(doms)
def brief_list(self, doms):
- print 'Name Id Mem(MB) CPU VCPU(s) State Time(s) Console'
+ print 'Name Id Mem(MB) CPU VCPU(s) State Time(s) Console SSID-REF'
for dom in doms:
info = server.xend_domain(dom)
d = {}
@@ -399,8 +399,12 @@ class ProgList(Prog):
d['port'] = sxp.child_value(console, 'console_port')
else:
d['port'] = ''
- print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s"
- % d)
+ if ((int(sxp.child_value(info, 'ssidref', '-1'))) != -1):
+ d['ssidref1'] = int(sxp.child_value(info, 'ssidref', '-1')) & 0xffff
+ d['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '-1')) >> 16) & 0xffff
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s s:%(ssidref2)02x/p:%(ssidref1)02x" % d)
+ else:
+ print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3d %(vcpus)5d %(state)5s %(cpu_time)7.1f %(port)4s default" % d)
def show_vcpus(self, doms):
print 'Name Id VCPU CPU CPUMAP'
diff --git a/tools/python/xen/xm/opts.py b/tools/python/xen/xm/opts.py
index f92c82dfe6..30900450dc 100644
--- a/tools/python/xen/xm/opts.py
+++ b/tools/python/xen/xm/opts.py
@@ -451,6 +451,13 @@ def set_bool(opt, k, v):
else:
opt.opts.err('Invalid value:' +v)
+def set_u32(opt, k, v):
+ """Set an option to an u32 value."""
+ try:
+ v = u32(v)
+ except:
+ opt.opts.err('Invalid value: ' + str(v))
+ opt.set(v)
def set_value(opt, k, v):
"""Set an option to a value."""
diff --git a/xen/Makefile b/xen/Makefile
index e71898cf4d..15b55fb24d 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -46,6 +46,7 @@ clean: delete-unfresh-files
$(MAKE) -C tools clean
$(MAKE) -C common clean
$(MAKE) -C drivers clean
+ $(MAKE) -C acm clean
$(MAKE) -C arch/$(TARGET_ARCH) clean
rm -f include/asm *.o $(TARGET)* *~ core
rm -f include/asm-*/asm-offsets.h
@@ -58,6 +59,7 @@ $(TARGET): delete-unfresh-files
$(MAKE) include/asm-$(TARGET_ARCH)/asm-offsets.h
$(MAKE) -C common
$(MAKE) -C drivers
+ $(MAKE) -C acm
$(MAKE) -C arch/$(TARGET_ARCH)
# drivers/char/console.o may contain static banner/compile info. Blow it away.
@@ -109,7 +111,7 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s
.PHONY: default debug install dist clean delete-unfresh-files TAGS tags
-SUBDIRS = arch/$(TARGET_ARCH) common drivers
+SUBDIRS = acm arch/$(TARGET_ARCH) common drivers
define all_sources
( find include/asm-$(TARGET_ARCH) -name SCCS -prune -o -name '*.h' -print; \
find include -type d -name SCCS -prune -o \( -name "asm-*" -o \
diff --git a/xen/Rules.mk b/xen/Rules.mk
index 221882814a..c0b13ae368 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -35,6 +35,7 @@ OBJS += $(patsubst %.c,%.o,$(C_SRCS))
ALL_OBJS := $(BASEDIR)/common/common.o
ALL_OBJS += $(BASEDIR)/drivers/char/driver.o
ALL_OBJS += $(BASEDIR)/drivers/acpi/driver.o
+ALL_OBJS += $(BASEDIR)/acm/acm.o
ALL_OBJS += $(BASEDIR)/arch/$(TARGET_ARCH)/arch.o
diff --git a/xen/acm/Makefile b/xen/acm/Makefile
new file mode 100644
index 0000000000..b212041afa
--- /dev/null
+++ b/xen/acm/Makefile
@@ -0,0 +1,15 @@
+
+include $(BASEDIR)/Rules.mk
+OBJS = acm_core.o
+OBJS += acm_policy.o
+OBJS += acm_simple_type_enforcement_hooks.o
+OBJS += acm_chinesewall_hooks.o
+OBJS += acm_null_hooks.o
+
+default: acm.o
+
+acm.o: $(OBJS)
+ $(LD) $(LDFLAGS) -r -o acm.o $(OBJS)
+
+clean:
+ rm -f *.o *~ core
diff --git a/xen/acm/acm_chinesewall_hooks.c b/xen/acm/acm_chinesewall_hooks.c
new file mode 100644
index 0000000000..938716d3f9
--- /dev/null
+++ b/xen/acm/acm_chinesewall_hooks.c
@@ -0,0 +1,503 @@
+/****************************************************************
+ * acm_chinesewall_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.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 of the
+ * License.
+ *
+ * sHype Chinese Wall Policy for Xen
+ * This code implements the hooks that are called
+ * throughout Xen operations and decides authorization
+ * based on domain types and Chinese Wall conflict type
+ * sets. The CHWALL policy decides if a new domain can be started
+ * based on the types of running domains and the type of the
+ * new domain to be started. If the new domain's type is in
+ * conflict with types of running domains, then this new domain
+ * is not allowed to be created. A domain can have multiple types,
+ * in which case all types of a new domain must be conflict-free
+ * with all types of already running domains.
+ *
+ */
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <asm/atomic.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct chwall_binary_policy chwall_bin_pol;
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_chwall_policy(void)
+{
+ /* minimal startup policy; policy write-locked already */
+ chwall_bin_pol.max_types = 1;
+ chwall_bin_pol.max_ssidrefs = 1;
+ chwall_bin_pol.max_conflictsets = 1;
+ chwall_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types);
+ chwall_bin_pol.conflict_sets = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types);
+ chwall_bin_pol.running_types = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+ chwall_bin_pol.conflict_aggregate_set = (domaintype_t *)xmalloc_array(domaintype_t, chwall_bin_pol.max_types);
+
+ if ((chwall_bin_pol.conflict_sets == NULL) || (chwall_bin_pol.running_types == NULL) ||
+ (chwall_bin_pol.ssidrefs == NULL) || (chwall_bin_pol.conflict_aggregate_set == NULL))
+ return ACM_INIT_SSID_ERROR;
+
+ /* initialize state */
+ memset((void *)chwall_bin_pol.ssidrefs, 0, chwall_bin_pol.max_ssidrefs*chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.conflict_sets, 0, chwall_bin_pol.max_conflictsets*chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.running_types, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
+ memset((void *)chwall_bin_pol.conflict_aggregate_set, 0, chwall_bin_pol.max_types*sizeof(domaintype_t));
+ return ACM_OK;
+}
+
+static int
+chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+ struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
+ traceprintk("%s.\n", __func__);
+ if (chwall_ssidp == NULL)
+ return ACM_INIT_SSID_ERROR;
+ /*
+ * depending on wheter chwall is primary or secondary, get the respective
+ * part of the global ssidref (same way we'll get the partial ssid pointer)
+ */
+ chwall_ssidp->chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ if (chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+ printkd("%s: ERROR chwall_ssidref(%x) > max(%x).\n",
+ __func__, chwall_ssidp->chwall_ssidref, chwall_bin_pol.max_ssidrefs-1);
+ xfree(chwall_ssidp);
+ return ACM_INIT_SSID_ERROR;
+ }
+ (*chwall_ssid) = chwall_ssidp;
+ printkd("%s: determined chwall_ssidref to %x.\n",
+ __func__, chwall_ssidp->chwall_ssidref);
+ return ACM_OK;
+}
+
+static void
+chwall_free_domain_ssid(void *chwall_ssid)
+{
+ traceprintk("%s.\n", __func__);
+ if (chwall_ssid != NULL)
+ xfree(chwall_ssid);
+ return;
+}
+
+
+/* dump chinese wall cache; policy read-locked already */
+static int
+chwall_dump_policy(u8 *buf, u16 buf_size) {
+ struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+ int ret = 0;
+
+ chwall_buf->chwall_max_types = htons(chwall_bin_pol.max_types);
+ chwall_buf->chwall_max_ssidrefs = htons(chwall_bin_pol.max_ssidrefs);
+ chwall_buf->policy_code = htons(ACM_CHINESE_WALL_POLICY);
+ chwall_buf->chwall_ssid_offset = htons(sizeof(struct acm_chwall_policy_buffer));
+ chwall_buf->chwall_max_conflictsets = htons(chwall_bin_pol.max_conflictsets);
+ chwall_buf->chwall_conflict_sets_offset =
+ htons(
+ ntohs(chwall_buf->chwall_ssid_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs *
+ chwall_bin_pol.max_types);
+
+ chwall_buf->chwall_running_types_offset =
+ htons(
+ ntohs(chwall_buf->chwall_conflict_sets_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
+ chwall_bin_pol.max_types);
+
+ chwall_buf->chwall_conflict_aggregate_offset =
+ htons(
+ ntohs(chwall_buf->chwall_running_types_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_types);
+
+ ret = ntohs(chwall_buf->chwall_conflict_aggregate_offset) +
+ sizeof(domaintype_t) * chwall_bin_pol.max_types;
+
+ /* now copy buffers over */
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_ssid_offset)),
+ chwall_bin_pol.ssidrefs,
+ chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_sets_offset)),
+ chwall_bin_pol.conflict_sets,
+ chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_running_types_offset)),
+ chwall_bin_pol.running_types,
+ chwall_bin_pol.max_types);
+
+ arrcpy16((u16 *)(buf + ntohs(chwall_buf->chwall_conflict_aggregate_offset)),
+ chwall_bin_pol.conflict_aggregate_set,
+ chwall_bin_pol.max_types);
+ return ret;
+}
+
+/* adapt security state (running_types and conflict_aggregate_set) to all running
+ * domains; chwall_init_state is called when a policy is changed to bring the security
+ * information into a consistent state and to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started
+ */
+static int
+chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf, domaintype_t *ssidrefs, domaintype_t *conflict_sets,
+ domaintype_t *running_types, domaintype_t *conflict_aggregate_set)
+{
+ int violation = 0, i, j;
+ struct chwall_ssid *chwall_ssid;
+ ssidref_t chwall_ssidref;
+ struct domain **pd;
+
+ write_lock(&domlist_lock);
+ /* go through all domains and adjust policy as if this domain was started now */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ chwall_ssid = GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)(*pd)->ssid);
+ chwall_ssidref = chwall_ssid->chwall_ssidref;
+ traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
+ __func__, (*pd)->domain_id, chwall_ssidref);
+ /* a) adjust types ref-count for running domains */
+ for (i=0; i< chwall_buf->chwall_max_types; i++)
+ running_types[i] +=
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i];
+
+ /* b) check for conflict */
+ for (i=0; i< chwall_buf->chwall_max_types; i++)
+ if (conflict_aggregate_set[i] &&
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + i]) {
+ printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+ violation = 1;
+ goto out;
+ }
+ /* set violation and break out of the loop */
+ /* c) adapt conflict aggregate set for this domain (notice conflicts) */
+ for (i=0; i<chwall_buf->chwall_max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_buf->chwall_max_types; j++)
+ if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+ ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_buf->chwall_max_types; j++)
+ if (conflict_sets[i*chwall_buf->chwall_max_types + j] &&
+ !ssidrefs[chwall_ssidref*chwall_buf->chwall_max_types + j])
+ conflict_aggregate_set[j]++;
+ }
+ }
+ out:
+ write_unlock(&domlist_lock);
+ return violation;
+ /* returning "violation != 0" means that the currently running set of domains would
+ * not be possible if the new policy had been enforced before starting them; for chinese
+ * wall, this means that the new policy includes at least one conflict set of which
+ * more than one type is currently running */
+}
+
+static int
+chwall_set_policy(u8 *buf, u16 buf_size)
+{
+ /* policy write-locked already */
+ struct acm_chwall_policy_buffer *chwall_buf = (struct acm_chwall_policy_buffer *)buf;
+ void *ssids = NULL, *conflict_sets = NULL, *running_types = NULL, *conflict_aggregate_set = NULL;
+
+ /* rewrite the policy due to endianess */
+ chwall_buf->policy_code = ntohs(chwall_buf->policy_code);
+ chwall_buf->chwall_max_types = ntohs(chwall_buf->chwall_max_types);
+ chwall_buf->chwall_max_ssidrefs = ntohs(chwall_buf->chwall_max_ssidrefs);
+ chwall_buf->chwall_max_conflictsets = ntohs(chwall_buf->chwall_max_conflictsets);
+ chwall_buf->chwall_ssid_offset = ntohs(chwall_buf->chwall_ssid_offset);
+ chwall_buf->chwall_conflict_sets_offset = ntohs(chwall_buf->chwall_conflict_sets_offset);
+ chwall_buf->chwall_running_types_offset = ntohs(chwall_buf->chwall_running_types_offset);
+ chwall_buf->chwall_conflict_aggregate_offset = ntohs(chwall_buf->chwall_conflict_aggregate_offset);
+
+ /* 1. allocate new buffers */
+ ssids = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types*chwall_buf->chwall_max_ssidrefs);
+ conflict_sets = xmalloc_array(domaintype_t, chwall_buf->chwall_max_conflictsets*chwall_buf->chwall_max_types);
+ running_types = xmalloc_array(domaintype_t,chwall_buf->chwall_max_types);
+ conflict_aggregate_set = xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
+
+ if ((ssids == NULL)||(conflict_sets == NULL)||(running_types == NULL)||(conflict_aggregate_set == NULL))
+ goto error_free;
+
+ /* 2. set new policy */
+ if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) *
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs > buf_size)
+ goto error_free;
+ arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
+ sizeof(domaintype_t),
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
+
+ if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) *
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets > buf_size)
+ goto error_free;
+
+ arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
+ sizeof(domaintype_t),
+ chwall_buf->chwall_max_types * chwall_buf->chwall_max_conflictsets);
+
+ /* we also use new state buffers since max_types can change */
+ memset(running_types, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+ memset(conflict_aggregate_set, 0, sizeof(domaintype_t)*chwall_buf->chwall_max_types);
+
+ /* 3. now re-calculate the state for the new policy based on running domains;
+ * this can fail if new policy is conflicting with running domains */
+ if (chwall_init_state(chwall_buf, ssids, conflict_sets, running_types, conflict_aggregate_set)) {
+ printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+ goto error_free; /* new policy conflicts with running domains */
+ }
+ /* 4. free old policy buffers, replace with new ones */
+ chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
+ chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
+ chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
+ if (chwall_bin_pol.ssidrefs != NULL)
+ xfree(chwall_bin_pol.ssidrefs);
+ if (chwall_bin_pol.conflict_aggregate_set != NULL)
+ xfree(chwall_bin_pol.conflict_aggregate_set);
+ if (chwall_bin_pol.running_types != NULL)
+ xfree(chwall_bin_pol.running_types);
+ if (chwall_bin_pol.conflict_sets != NULL)
+ xfree(chwall_bin_pol.conflict_sets);
+ chwall_bin_pol.ssidrefs = ssids;
+ chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
+ chwall_bin_pol.running_types = running_types;
+ chwall_bin_pol.conflict_sets = conflict_sets;
+ return ACM_OK;
+
+error_free:
+ printk("%s: ERROR setting policy.\n", __func__);
+ if (ssids != NULL) xfree(ssids);
+ if (conflict_sets != NULL) xfree(conflict_sets);
+ if (running_types != NULL) xfree(running_types);
+ if (conflict_aggregate_set != NULL) xfree(conflict_aggregate_set);
+ return -EFAULT;
+}
+
+static int
+chwall_dump_stats(u8 *buf, u16 len)
+{
+ /* no stats for Chinese Wall Policy */
+ return 0;
+}
+
+/***************************
+ * Authorization functions
+ ***************************/
+
+
+/* -------- DOMAIN OPERATION HOOKS -----------*/
+
+static int
+chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ ssidref_t chwall_ssidref;
+ int i,j;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+ printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED; /* catching and indicating config error */
+ }
+ if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs) {
+ printk("%s: ERROR chwall_ssidref > max(%x).\n",
+ __func__, chwall_bin_pol.max_ssidrefs-1);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+ /* A: chinese wall check for conflicts */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ if (chwall_bin_pol.conflict_aggregate_set[i] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i]) {
+ printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+
+ /* B: chinese wall conflict set adjustment (so that other
+ * other domains simultaneously created are evaluated against this new set)*/
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]++;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_PERMITTED;
+}
+
+static void
+chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
+{
+ int i,j;
+ ssidref_t chwall_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ /* adjust types ref-count for running domains */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ chwall_bin_pol.running_types[i] +=
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+ if (domid) {
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+ }
+ /* Xen does not call pre-create hook for DOM0;
+ * to consider type conflicts of any domain with DOM0, we need
+ * to adjust the conflict_aggregate for DOM0 here the same way it
+ * is done for non-DOM0 domains in the pre-hook */
+ printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n",
+ __func__, ssidref, chwall_ssidref);
+
+ /* chinese wall conflict set adjustment (so that other
+ * other domains simultaneously created are evaluated against this new set)*/
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]++;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+}
+
+static void
+chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ int i, j;
+ ssidref_t chwall_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
+ /* roll-back: re-adjust conflicting types aggregate */
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]--;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+}
+
+
+static void
+chwall_post_domain_destroy(void *object_ssid, domid_t id)
+{
+ int i,j;
+ struct chwall_ssid *chwall_ssidp =
+ GET_SSIDP(ACM_CHINESE_WALL_POLICY, (struct acm_ssid_domain *)object_ssid);
+ ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
+
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ /* adjust running types set */
+ for (i=0; i< chwall_bin_pol.max_types; i++)
+ chwall_bin_pol.running_types[i] -=
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + i];
+
+ /* roll-back: re-adjust conflicting types aggregate */
+ for (i=0; i<chwall_bin_pol.max_conflictsets; i++) {
+ int common = 0;
+ /* check if conflict_set_i and ssidref have common types */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j]) {
+ common = 1;
+ break;
+ }
+ if (common == 0)
+ continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
+ /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
+ for (j=0; j<chwall_bin_pol.max_types; j++)
+ if (chwall_bin_pol.conflict_sets[i*chwall_bin_pol.max_types + j] &&
+ !chwall_bin_pol.ssidrefs[chwall_ssidref*chwall_bin_pol.max_types + j])
+ chwall_bin_pol.conflict_aggregate_set[j]--;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return;
+}
+
+struct acm_operations acm_chinesewall_ops = {
+ /* policy management services */
+ .init_domain_ssid = chwall_init_domain_ssid,
+ .free_domain_ssid = chwall_free_domain_ssid,
+ .dump_binary_policy = chwall_dump_policy,
+ .set_binary_policy = chwall_set_policy,
+ .dump_statistics = chwall_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = chwall_pre_domain_create,
+ .post_domain_create = chwall_post_domain_create,
+ .fail_domain_create = chwall_fail_domain_create,
+ .post_domain_destroy = chwall_post_domain_destroy,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = NULL,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = NULL,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = NULL,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = NULL,
+ .fail_grant_setup = NULL,
+};
diff --git a/xen/acm/acm_core.c b/xen/acm/acm_core.c
new file mode 100644
index 0000000000..fe5bacdb6d
--- /dev/null
+++ b/xen/acm/acm_core.c
@@ -0,0 +1,205 @@
+/****************************************************************
+ * acm_core.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * sHype access control module (ACM)
+ * This file handles initialization of the ACM
+ * as well as initializing/freeing security
+ * identifiers for domains (it calls on active
+ * policy hook functions).
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+/* debug:
+ * include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE;
+ * define/undefine this constant to receive / suppress any
+ * security hook debug output of sHype
+ *
+ * include/public/acm.h defines a constant ACM_DEBUG
+ * define/undefine this constant to receive non-hook-related
+ * debug output.
+ */
+
+/* function prototypes */
+void acm_init_chwall_policy(void);
+void acm_init_ste_policy(void);
+
+extern struct acm_operations acm_chinesewall_ops,
+ acm_simple_type_enforcement_ops, acm_null_ops;
+
+/* global ops structs called by the hooks */
+struct acm_operations *acm_primary_ops = NULL;
+/* called in hook if-and-only-if primary succeeds */
+struct acm_operations *acm_secondary_ops = NULL;
+
+/* acm global binary policy (points to 'local' primary and secondary policies */
+struct acm_binary_policy acm_bin_pol;
+/* acm binary policy lock */
+rwlock_t acm_bin_pol_rwlock = RW_LOCK_UNLOCKED;
+
+/* until we have endian support in Xen, we discover it at runtime */
+u8 little_endian = 1;
+void acm_set_endian(void)
+{
+ u32 test = 1;
+ if (*((u8 *)&test) == 1) {
+ printk("ACM module running in LITTLE ENDIAN.\n");
+ little_endian = 1;
+ } else {
+ printk("ACM module running in BIG ENDIAN.\n");
+ little_endian = 0;
+ }
+}
+
+/* initialize global security policy for Xen; policy write-locked already */
+static void
+acm_init_binary_policy(void *primary, void *secondary)
+{
+ acm_bin_pol.primary_policy_code = 0;
+ acm_bin_pol.secondary_policy_code = 0;
+ acm_bin_pol.primary_binary_policy = primary;
+ acm_bin_pol.secondary_binary_policy = secondary;
+}
+
+int
+acm_init(void)
+{
+ int ret = -EINVAL;
+
+ acm_set_endian();
+ write_lock(&acm_bin_pol_rwlock);
+
+ if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_chwall_policy();
+ acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+ acm_primary_ops = &acm_chinesewall_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_ste_policy();
+ acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ acm_primary_ops = &acm_simple_type_enforcement_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_init_chwall_policy();
+ acm_init_ste_policy();
+ acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
+ acm_primary_ops = &acm_chinesewall_ops;
+ acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
+ acm_secondary_ops = &acm_simple_type_enforcement_ops;
+ ret = ACM_OK;
+ } else if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY) {
+ acm_init_binary_policy(NULL, NULL);
+ acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
+ acm_primary_ops = &acm_null_ops;
+ acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
+ acm_secondary_ops = &acm_null_ops;
+ ret = ACM_OK;
+ }
+ write_unlock(&acm_bin_pol_rwlock);
+
+ if (ret != ACM_OK)
+ return -EINVAL;
+ printk("%s: Enforcing Primary %s, Secondary %s.\n", __func__,
+ ACM_POLICY_NAME(acm_bin_pol.primary_policy_code), ACM_POLICY_NAME(acm_bin_pol.secondary_policy_code));
+ return ACM_OK;
+}
+
+
+int
+acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
+{
+ struct acm_ssid_domain *ssid;
+ struct domain *subj = find_domain_by_id(id);
+ int ret1, ret2;
+
+ if (subj == NULL) {
+ printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
+ return ACM_NULL_POINTER_ERROR;
+ }
+ if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ ssid->datatype = DOMAIN;
+ ssid->subject = subj;
+ ssid->domainid = subj->domain_id;
+ ssid->primary_ssid = NULL;
+ ssid->secondary_ssid = NULL;
+
+ if (ACM_USE_SECURITY_POLICY != ACM_NULL_POLICY)
+ ssid->ssidref = ssidref;
+ else
+ ssid->ssidref = ACM_DEFAULT_SSID;
+
+ subj->ssid = ssid;
+ /* now fill in primary and secondary parts; we only get here through hooks */
+ if (acm_primary_ops->init_domain_ssid != NULL)
+ ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
+ else
+ ret1 = ACM_OK;
+
+ if (acm_secondary_ops->init_domain_ssid != NULL)
+ ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
+ else
+ ret2 = ACM_OK;
+
+ if ((ret1 != ACM_OK) || (ret2 != ACM_OK)) {
+ printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
+ __func__, subj->domain_id);
+ acm_free_domain_ssid(ssid);
+ put_domain(subj);
+ return ACM_INIT_SSID_ERROR;
+ }
+ printk("%s: assigned domain %x the ssidref=%x.\n", __func__, id, ssid->ssidref);
+ put_domain(subj);
+ return ACM_OK;
+}
+
+
+int
+acm_free_domain_ssid(struct acm_ssid_domain *ssid)
+{
+ domid_t id;
+
+ /* domain is already gone, just ssid is left */
+ if (ssid == NULL) {
+ printk("%s: ACM_NULL_POINTER ERROR.\n", __func__);
+ return ACM_NULL_POINTER_ERROR;
+ }
+ id = ssid->domainid;
+ ssid->subject = NULL;
+
+ if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
+ acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
+ ssid->primary_ssid = NULL;
+ if (acm_secondary_ops->free_domain_ssid != NULL)
+ acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
+ ssid->secondary_ssid = NULL;
+ xfree(ssid);
+ printkd("%s: Freed individual domain ssid (domain=%02x).\n",__func__, id);
+ return ACM_OK;
+}
diff --git a/xen/acm/acm_null_hooks.c b/xen/acm/acm_null_hooks.c
new file mode 100644
index 0000000000..6433cbfed6
--- /dev/null
+++ b/xen/acm/acm_null_hooks.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * acm_null_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ */
+#include <acm/acm_hooks.h>
+
+static int
+null_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
+{
+ return ACM_OK;
+}
+
+
+static void
+null_free_domain_ssid(void *chwall_ssid)
+{
+ return;
+}
+
+
+static int
+null_dump_binary_policy(u8 *buf, u16 buf_size)
+{
+ return 0;
+}
+
+
+
+static int
+null_set_binary_policy(u8 *buf, u16 buf_size)
+{
+ return -1;
+}
+
+
+static int
+null_dump_stats(u8 *buf, u16 buf_size)
+{
+ /* no stats for NULL policy */
+ return 0;
+}
+
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_null_ops = {
+ .init_domain_ssid = null_init_domain_ssid,
+ .free_domain_ssid = null_free_domain_ssid,
+ .dump_binary_policy = null_dump_binary_policy,
+ .set_binary_policy = null_set_binary_policy,
+ .dump_statistics = null_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = NULL,
+ .post_domain_create = NULL,
+ .fail_domain_create = NULL,
+ .post_domain_destroy = NULL,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = NULL,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = NULL,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = NULL,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = NULL,
+ .fail_grant_setup = NULL
+
+};
diff --git a/xen/acm/acm_policy.c b/xen/acm/acm_policy.c
new file mode 100644
index 0000000000..3e08130d43
--- /dev/null
+++ b/xen/acm/acm_policy.c
@@ -0,0 +1,197 @@
+/****************************************************************
+ * acm_policy.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributions:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * support for network-byte-order binary policies
+ *
+ * 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 of the
+ * License.
+ *
+ * sHype access control policy management for Xen.
+ * This interface allows policy tools in authorized
+ * domains to interact with the Xen access control module
+ *
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/policy_ops.h>
+#include <acm/acm_core.h>
+#include <acm/acm_hooks.h>
+#include <acm/acm_endian.h>
+
+int
+acm_set_policy(void *buf, u16 buf_size, u16 policy)
+{
+ u8 *policy_buffer = NULL;
+ struct acm_policy_buffer *pol;
+
+ if (policy != ACM_USE_SECURITY_POLICY) {
+ printk("%s: Loading incompatible policy (running: %s).\n", __func__,
+ ACM_POLICY_NAME(ACM_USE_SECURITY_POLICY));
+ return -EFAULT;
+ }
+ /* now check correct buffer sizes for policy combinations */
+ if (policy == ACM_NULL_POLICY) {
+ printkd("%s: NULL Policy, no policy needed.\n", __func__);
+ goto out;
+ }
+ if (buf_size < sizeof(struct acm_policy_buffer))
+ return -EFAULT;
+ /* 1. copy buffer from domain */
+ if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ goto error_free;
+ if (copy_from_user(policy_buffer, buf, buf_size)) {
+ printk("%s: Error copying!\n",__func__);
+ goto error_free;
+ }
+ /* 2. some sanity checking */
+ pol = (struct acm_policy_buffer *)policy_buffer;
+
+ if ((ntohl(pol->magic) != ACM_MAGIC) ||
+ (ntohs(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
+ (ntohs(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code)) {
+ printkd("%s: Wrong policy magics!\n", __func__);
+ goto error_free;
+ }
+ if (buf_size != ntohl(pol->len)) {
+ printk("%s: ERROR in buf size.\n", __func__);
+ goto error_free;
+ }
+
+ /* get bin_policy lock and rewrite policy (release old one) */
+ write_lock(&acm_bin_pol_rwlock);
+
+ /* 3. now get/set primary policy data */
+ if (acm_primary_ops->set_binary_policy(buf + ntohs(pol->primary_buffer_offset),
+ ntohs(pol->secondary_buffer_offset) -
+ ntohs(pol->primary_buffer_offset))) {
+ goto error_lock_free;
+ }
+ /* 4. now get/set secondary policy data */
+ if (acm_secondary_ops->set_binary_policy(buf + ntohs(pol->secondary_buffer_offset),
+ ntohl(pol->len) -
+ ntohs(pol->secondary_buffer_offset))) {
+ goto error_lock_free;
+ }
+ write_unlock(&acm_bin_pol_rwlock);
+ out:
+ printk("%s: Done .\n", __func__);
+ if (policy_buffer != NULL)
+ xfree(policy_buffer);
+ return ACM_OK;
+
+ error_lock_free:
+ write_unlock(&acm_bin_pol_rwlock);
+ error_free:
+ printk("%s: Error setting policy.\n", __func__);
+ if (policy_buffer != NULL)
+ xfree(policy_buffer);
+ return -ENOMEM;
+}
+
+int
+acm_get_policy(void *buf, u16 buf_size)
+{
+ u8 *policy_buffer;
+ int ret;
+ struct acm_policy_buffer *bin_pol;
+
+ if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ return -ENOMEM;
+
+ read_lock(&acm_bin_pol_rwlock);
+ /* future: read policy from file and set it */
+ bin_pol = (struct acm_policy_buffer *)policy_buffer;
+ bin_pol->magic = htonl(ACM_MAGIC);
+ bin_pol->policyversion = htonl(POLICY_INTERFACE_VERSION);
+ bin_pol->primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+ bin_pol->secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+
+ bin_pol->len = htonl(sizeof(struct acm_policy_buffer));
+ bin_pol->primary_buffer_offset = htons(ntohl(bin_pol->len));
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+
+ ret = acm_primary_ops->dump_binary_policy (policy_buffer + ntohs(bin_pol->primary_buffer_offset),
+ buf_size - ntohs(bin_pol->primary_buffer_offset));
+ if (ret < 0) {
+ printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ bin_pol->secondary_buffer_offset = htons(ntohl(bin_pol->len));
+
+ ret = acm_secondary_ops->dump_binary_policy(policy_buffer + ntohs(bin_pol->secondary_buffer_offset),
+ buf_size - ntohs(bin_pol->secondary_buffer_offset));
+ if (ret < 0) {
+ printk("%s: ERROR creating chwallpolicy buffer.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return -1;
+ }
+ bin_pol->len = htonl(ntohl(bin_pol->len) + ret);
+ read_unlock(&acm_bin_pol_rwlock);
+ if (copy_to_user(buf, policy_buffer, ntohl(bin_pol->len)))
+ return -EFAULT;
+ xfree(policy_buffer);
+ return ACM_OK;
+}
+
+int
+acm_dump_statistics(void *buf, u16 buf_size)
+{
+ /* send stats to user space */
+ u8 *stats_buffer;
+ int len1, len2;
+ struct acm_stats_buffer acm_stats;
+
+ if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
+ return -ENOMEM;
+
+ read_lock(&acm_bin_pol_rwlock);
+
+ len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
+ buf_size - sizeof(struct acm_stats_buffer));
+ if (len1 < 0)
+ goto error_lock_free;
+
+ len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
+ buf_size - sizeof(struct acm_stats_buffer) - len1);
+ if (len2 < 0)
+ goto error_lock_free;
+
+ acm_stats.magic = htonl(ACM_MAGIC);
+ acm_stats.policyversion = htonl(POLICY_INTERFACE_VERSION);
+ acm_stats.primary_policy_code = htons(acm_bin_pol.primary_policy_code);
+ acm_stats.secondary_policy_code = htons(acm_bin_pol.secondary_policy_code);
+ acm_stats.primary_stats_offset = htons(sizeof(struct acm_stats_buffer));
+ acm_stats.secondary_stats_offset = htons(sizeof(struct acm_stats_buffer) + len1);
+ acm_stats.len = htonl(sizeof(struct acm_stats_buffer) + len1 + len2);
+ memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
+
+ if (copy_to_user(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
+ goto error_lock_free;
+
+ read_unlock(&acm_bin_pol_rwlock);
+ xfree(stats_buffer);
+ return ACM_OK;
+
+ error_lock_free:
+ read_unlock(&acm_bin_pol_rwlock);
+ xfree(stats_buffer);
+ return -EFAULT;
+}
+
+/*eof*/
diff --git a/xen/acm/acm_simple_type_enforcement_hooks.c b/xen/acm/acm_simple_type_enforcement_hooks.c
new file mode 100644
index 0000000000..17e75deca8
--- /dev/null
+++ b/xen/acm/acm_simple_type_enforcement_hooks.c
@@ -0,0 +1,638 @@
+/****************************************************************
+ * acm_simple_type_enforcement_hooks.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * support for network order binary policies
+ *
+ * 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 of the
+ * License.
+ *
+ * sHype Simple Type Enforcement for Xen
+ * STE allows to control which domains can setup sharing
+ * (eventchannels right now) with which other domains. Hooks
+ * are defined and called throughout Xen when domains bind to
+ * shared resources (setup eventchannels) and a domain is allowed
+ * to setup sharing with another domain if and only if both domains
+ * share at least on common type.
+ *
+ */
+#include <xen/lib.h>
+#include <asm/types.h>
+#include <asm/current.h>
+#include <acm/acm_hooks.h>
+#include <asm/atomic.h>
+#include <acm/acm_endian.h>
+
+/* local cache structures for chinese wall policy */
+struct ste_binary_policy ste_bin_pol;
+
+static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
+ int i;
+ for(i=0; i< ste_bin_pol.max_types; i++)
+ if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
+ ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
+ printkd("%s: common type #%02x.\n", __func__, i);
+ return 1;
+ }
+ return 0;
+}
+
+/* Helper function: return = (subj and obj share a common type) */
+static int share_common_type(struct domain *subj, struct domain *obj)
+{
+ ssidref_t ref_s, ref_o;
+ int ret;
+
+ if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
+ return 0;
+ read_lock(&acm_bin_pol_rwlock);
+ /* lookup the policy-local ssids */
+ ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
+ ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
+ /* check whether subj and obj share a common ste type */
+ ret = have_common_type(ref_s, ref_o);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ret;
+}
+
+/*
+ * Initializing chinese wall policy (will be filled by policy partition
+ * using setpolicy command)
+ */
+int acm_init_ste_policy(void)
+{
+ /* minimal startup policy; policy write-locked already */
+ ste_bin_pol.max_types = 1;
+ ste_bin_pol.max_ssidrefs = 1;
+ ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 1);
+
+ if (ste_bin_pol.ssidrefs == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ /* initialize state */
+ ste_bin_pol.ssidrefs[0] = 1;
+
+ /* init stats */
+ atomic_set(&(ste_bin_pol.ec_eval_count), 0);
+ atomic_set(&(ste_bin_pol.ec_denied_count), 0);
+ atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
+ atomic_set(&(ste_bin_pol.gt_eval_count), 0);
+ atomic_set(&(ste_bin_pol.gt_denied_count), 0);
+ atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
+ return ACM_OK;
+}
+
+
+/* ste initialization function hooks */
+static int
+ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
+{
+ int i;
+ struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
+ traceprintk("%s.\n", __func__);
+
+ if (ste_ssidp == NULL)
+ return ACM_INIT_SSID_ERROR;
+
+ /* get policy-local ssid reference */
+ ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+ if (ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+ printkd("%s: ERROR ste_ssidref (%x) > max(%x).\n",
+ __func__, ste_ssidp->ste_ssidref, ste_bin_pol.max_ssidrefs-1);
+ xfree(ste_ssidp);
+ return ACM_INIT_SSID_ERROR;
+ }
+ /* clean ste cache */
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ ste_ssidp->ste_cache[i].valid = FREE;
+
+ (*ste_ssid) = ste_ssidp;
+ printkd("%s: determined ste_ssidref to %x.\n",
+ __func__, ste_ssidp->ste_ssidref);
+ return ACM_OK;
+}
+
+
+static void
+ste_free_domain_ssid(void *ste_ssid)
+{
+ traceprintk("%s.\n", __func__);
+ if (ste_ssid != NULL)
+ xfree(ste_ssid);
+ return;
+}
+
+/* dump type enforcement cache; policy read-locked already */
+static int
+ste_dump_policy(u8 *buf, u16 buf_size) {
+ struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+ int ret = 0;
+
+ ste_buf->ste_max_types = htons(ste_bin_pol.max_types);
+ ste_buf->ste_max_ssidrefs = htons(ste_bin_pol.max_ssidrefs);
+ ste_buf->policy_code = htons(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
+ ste_buf->ste_ssid_offset = htons(sizeof(struct acm_ste_policy_buffer));
+ ret = ntohs(ste_buf->ste_ssid_offset) +
+ sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
+
+ /* now copy buffer over */
+ arrcpy(buf + ntohs(ste_buf->ste_ssid_offset),
+ ste_bin_pol.ssidrefs,
+ sizeof(domaintype_t),
+ ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
+
+ return ret;
+}
+
+/* ste_init_state is called when a policy is changed to detect violations (return != 0).
+ * from a security point of view, we simulate that all running domains are re-started and
+ * all sharing decisions are replayed to detect violations or current sharing behavior
+ * (right now: event_channels, future: also grant_tables)
+ */
+static int
+ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
+{
+ int violation = 1;
+ struct ste_ssid *ste_ssid, *ste_rssid;
+ ssidref_t ste_ssidref, ste_rssidref;
+ struct domain **pd, *rdom;
+ domid_t rdomid;
+ grant_entry_t sha_copy;
+ int port, i;
+
+ read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+ /* go through all domains and adjust policy as if this domain was started now */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ ste_ssidref = ste_ssid->ste_ssidref;
+ traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
+ __func__, (*pd)->domain_id, ste_ssidref);
+ /* a) check for event channel conflicts */
+ for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
+ spin_lock(&(*pd)->evtchn_lock);
+ if ((*pd)->evtchn[port] == NULL) {
+ spin_unlock(&(*pd)->evtchn_lock);
+ continue;
+ }
+ if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
+ rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
+ rdomid = rdom->domain_id;
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ } else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
+ rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
+ if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+ printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
+ goto out;
+ }
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ put_domain(rdom);
+ } else {
+ spin_unlock(&(*pd)->evtchn_lock);
+ continue; /* port unused */
+ }
+ spin_unlock(&(*pd)->evtchn_lock);
+
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
+ __func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
+ /* check whether on subj->ssid, obj->ssid share a common type*/
+ if (!have_common_type(ste_ssidref, ste_rssidref)) {
+ printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
+ __func__, (*pd)->domain_id, rdomid);
+ goto out;
+ }
+ }
+ /* b) check for grant table conflicts on shared pages */
+ if ((*pd)->grant_table->shared == NULL) {
+ printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
+ continue;
+ }
+ for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
+ sha_copy = (*pd)->grant_table->shared[i];
+ if ( sha_copy.flags ) {
+ printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
+ __func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid,
+ (unsigned long)sha_copy.frame);
+ rdomid = sha_copy.domid;
+ if ((rdom = find_domain_by_id(rdomid)) == NULL) {
+ printkd("%s: domain not found ERROR!\n", __func__);
+ goto out;
+ };
+ /* rdom now has remote domain */
+ ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(rdom->ssid));
+ ste_rssidref = ste_rssid->ste_ssidref;
+ put_domain(rdom);
+ if (!have_common_type(ste_ssidref, ste_rssidref)) {
+ printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
+ __func__, (*pd)->domain_id, rdomid);
+ goto out;
+ }
+ }
+ }
+ }
+ violation = 0;
+ out:
+ read_unlock(&domlist_lock);
+ return violation;
+ /* returning "violation != 0" means that existing sharing between domains would not
+ * have been allowed if the new policy had been enforced before the sharing; for ste,
+ * this means that there are at least 2 domains that have established sharing through
+ * event-channels or grant-tables but these two domains don't have no longer a common
+ * type in their typesets referenced by their ssidrefs */
+}
+
+/* set new policy; policy write-locked already */
+static int
+ste_set_policy(u8 *buf, u16 buf_size)
+{
+ struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
+ void *ssidrefsbuf;
+ struct ste_ssid *ste_ssid;
+ struct domain **pd;
+ int i;
+
+ /* Convert endianess of policy */
+ ste_buf->policy_code = ntohs(ste_buf->policy_code);
+ ste_buf->ste_max_types = ntohs(ste_buf->ste_max_types);
+ ste_buf->ste_max_ssidrefs = ntohs(ste_buf->ste_max_ssidrefs);
+ ste_buf->ste_ssid_offset = ntohs(ste_buf->ste_ssid_offset);
+
+ /* 1. create and copy-in new ssidrefs buffer */
+ ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
+ if (ssidrefsbuf == NULL) {
+ return -ENOMEM;
+ }
+ if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
+ goto error_free;
+
+ arrcpy(ssidrefsbuf,
+ buf + ste_buf->ste_ssid_offset,
+ sizeof(domaintype_t),
+ ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
+
+ /* 2. now re-calculate sharing decisions based on running domains;
+ * this can fail if new policy is conflicting with sharing of running domains
+ * now: reject violating new policy; future: adjust sharing through revoking sharing */
+ if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
+ printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
+ goto error_free; /* new policy conflicts with sharing of running domains */
+ }
+ /* 3. replace old policy (activate new policy) */
+ ste_bin_pol.max_types = ste_buf->ste_max_types;
+ ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
+ if (ste_bin_pol.ssidrefs)
+ xfree(ste_bin_pol.ssidrefs);
+ ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
+
+ /* clear all ste caches */
+ read_lock(&domlist_lock);
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ ste_ssid->ste_cache[i].valid = FREE;
+ }
+ read_unlock(&domlist_lock);
+ return ACM_OK;
+
+error_free:
+ printk("%s: ERROR setting policy.\n", __func__);
+ if (ssidrefsbuf != NULL) xfree(ssidrefsbuf);
+ return -EFAULT;
+}
+
+static int
+ste_dump_stats(u8 *buf, u16 buf_len)
+{
+ struct acm_ste_stats_buffer stats;
+
+#ifdef ACM_DEBUG
+ int i;
+ struct ste_ssid *ste_ssid;
+ struct domain **pd;
+
+ printk("ste: Decision caches:\n");
+ /* go through all domains and adjust policy as if this domain was started now */
+ read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ printk("ste: Cache Domain %02x.\n", (*pd)->domain_id);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ printk("\t\tcache[%02x] = %s, domid=%x.\n", i,
+ (ste_ssid->ste_cache[i].valid == VALID) ?
+ "VALID" : "FREE",
+ (ste_ssid->ste_cache[i].valid == VALID) ?
+ ste_ssid->ste_cache[i].id : 0xffffffff);
+ }
+ read_unlock(&domlist_lock);
+ /* init stats */
+ printk("STE-Policy Security Hook Statistics:\n");
+ printk("ste: event_channel eval_count = %x\n", atomic_read(&(ste_bin_pol.ec_eval_count)));
+ printk("ste: event_channel denied_count = %x\n", atomic_read(&(ste_bin_pol.ec_denied_count)));
+ printk("ste: event_channel cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.ec_cachehit_count)));
+ printk("ste:\n");
+ printk("ste: grant_table eval_count = %x\n", atomic_read(&(ste_bin_pol.gt_eval_count)));
+ printk("ste: grant_table denied_count = %x\n", atomic_read(&(ste_bin_pol.gt_denied_count)));
+ printk("ste: grant_table cache_hit_count = %x\n", atomic_read(&(ste_bin_pol.gt_cachehit_count)));
+#endif
+
+ if (buf_len < sizeof(struct acm_ste_stats_buffer))
+ return -ENOMEM;
+
+ /* now send the hook counts to user space */
+ stats.ec_eval_count = htonl(atomic_read(&ste_bin_pol.ec_eval_count));
+ stats.gt_eval_count = htonl(atomic_read(&ste_bin_pol.gt_eval_count));
+ stats.ec_denied_count = htonl(atomic_read(&ste_bin_pol.ec_denied_count));
+ stats.gt_denied_count = htonl(atomic_read(&ste_bin_pol.gt_denied_count));
+ stats.ec_cachehit_count = htonl(atomic_read(&ste_bin_pol.ec_cachehit_count));
+ stats.gt_cachehit_count = htonl(atomic_read(&ste_bin_pol.gt_cachehit_count));
+ memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
+ return sizeof(struct acm_ste_stats_buffer);
+}
+
+
+/* we need to go through this before calling the hooks,
+ * returns 1 == cache hit */
+static int inline
+check_cache(struct domain *dom, domid_t rdom) {
+ struct ste_ssid *ste_ssid;
+ int i;
+
+ printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(dom)->ssid);
+
+ for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
+ if ((ste_ssid->ste_cache[i].valid == VALID) &&
+ (ste_ssid->ste_cache[i].id == rdom)) {
+ printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* we only get here if there is NO entry yet; no duplication check! */
+static void inline
+cache_result(struct domain *subj, struct domain *obj) {
+ struct ste_ssid *ste_ssid;
+ int i;
+ printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(subj)->ssid);
+ for(i=0; i< ACM_TE_CACHE_SIZE; i++)
+ if (ste_ssid->ste_cache[i].valid == FREE)
+ break;
+ if (i< ACM_TE_CACHE_SIZE) {
+ ste_ssid->ste_cache[i].valid = VALID;
+ ste_ssid->ste_cache[i].id = obj->domain_id;
+ } else
+ printk ("Cache of dom %x is full!\n", subj->domain_id);
+}
+
+/* deletes entries for domain 'id' from all caches (re-use) */
+static void inline
+clean_id_from_cache(domid_t id)
+{
+ struct ste_ssid *ste_ssid;
+ int i;
+ struct domain **pd;
+
+ printkd("deleting cache for dom %x.\n", id);
+
+ read_lock(&domlist_lock); /* look through caches of all domains */
+ pd = &domain_list;
+ for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
+ ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
+ (struct acm_ssid_domain *)(*pd)->ssid);
+ for (i=0; i<ACM_TE_CACHE_SIZE; i++)
+ if ((ste_ssid->ste_cache[i].valid == VALID) &&
+ (ste_ssid->ste_cache[i].id = id))
+ ste_ssid->ste_cache[i].valid = FREE;
+ }
+ read_unlock(&domlist_lock);
+}
+
+/***************************
+ * Authorization functions
+ **************************/
+
+static int
+ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+{
+ /* check for ssidref in range for policy */
+ ssidref_t ste_ssidref;
+ traceprintk("%s.\n", __func__);
+
+ read_lock(&acm_bin_pol_rwlock);
+ ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
+ if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
+ printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED; /* catching and indicating config error */
+ }
+ if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
+ printk("%s: ERROR ste_ssidref > max(%x).\n",
+ __func__, ste_bin_pol.max_ssidrefs-1);
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_DENIED;
+ }
+ read_unlock(&acm_bin_pol_rwlock);
+ return ACM_ACCESS_PERMITTED;
+}
+
+static void
+ste_post_domain_destroy(void *subject_ssid, domid_t id)
+{
+ /* clean all cache entries for destroyed domain (might be re-used) */
+ clean_id_from_cache(id);
+}
+
+/* -------- EVENTCHANNEL OPERATIONS -----------*/
+static int
+ste_pre_eventchannel_unbound(domid_t id) {
+ struct domain *subj, *obj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n",
+ __func__, current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.ec_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.ec_eval_count);
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.ec_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+static int
+ste_pre_eventchannel_interdomain(domid_t id1, domid_t id2)
+{
+ struct domain *subj, *obj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
+ (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
+
+ /* following is a bit longer but ensures that we
+ * "put" only domains that we where "find"-ing
+ */
+ if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
+ if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
+
+ subj = find_domain_by_id(id1);
+ obj = find_domain_by_id(id2);
+ if ((subj == NULL) || (obj == NULL)) {
+ ret = ACM_ACCESS_DENIED;
+ goto out;
+ }
+ /* cache check late, but evtchn is not on performance critical path */
+ if (check_cache(subj, obj->domain_id)) {
+ atomic_inc(&ste_bin_pol.ec_cachehit_count);
+ ret = ACM_ACCESS_PERMITTED;
+ goto out;
+ }
+ atomic_inc(&ste_bin_pol.ec_eval_count);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.ec_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ out:
+ if (obj != NULL)
+ put_domain(obj);
+ if (subj != NULL)
+ put_domain(subj);
+ return ret;
+}
+
+/* -------- SHARED MEMORY OPERATIONS -----------*/
+
+static int
+ste_pre_grant_map_ref (domid_t id) {
+ struct domain *obj, *subj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.gt_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.gt_eval_count);
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.gt_denied_count);
+ printkd("%s: ACCESS DENIED!\n", __func__);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+/* since setting up grant tables involves some implicit information
+ flow from the creating domain to the domain that is setup, we
+ check types in addition to the general authorization */
+static int
+ste_pre_grant_setup (domid_t id) {
+ struct domain *obj, *subj;
+ int ret;
+ traceprintk("%s: dom%x-->dom%x.\n", __func__,
+ current->domain->domain_id, id);
+
+ if (check_cache(current->domain, id)) {
+ atomic_inc(&ste_bin_pol.gt_cachehit_count);
+ return ACM_ACCESS_PERMITTED;
+ }
+ atomic_inc(&ste_bin_pol.gt_eval_count);
+ /* a) check authorization (eventually use specific capabilities) */
+ if (!IS_PRIV(current->domain)) {
+ printk("%s: Grant table management authorization denied ERROR!\n", __func__);
+ return ACM_ACCESS_DENIED;
+ }
+ /* b) check types */
+ subj = current->domain;
+ obj = find_domain_by_id(id);
+
+ if (share_common_type(subj, obj)) {
+ cache_result(subj, obj);
+ ret = ACM_ACCESS_PERMITTED;
+ } else {
+ atomic_inc(&ste_bin_pol.gt_denied_count);
+ ret = ACM_ACCESS_DENIED;
+ }
+ if (obj != NULL)
+ put_domain(obj);
+ return ret;
+}
+
+/* now define the hook structure similarly to LSM */
+struct acm_operations acm_simple_type_enforcement_ops = {
+ /* policy management services */
+ .init_domain_ssid = ste_init_domain_ssid,
+ .free_domain_ssid = ste_free_domain_ssid,
+ .dump_binary_policy = ste_dump_policy,
+ .set_binary_policy = ste_set_policy,
+ .dump_statistics = ste_dump_stats,
+ /* domain management control hooks */
+ .pre_domain_create = ste_pre_domain_create,
+ .post_domain_create = NULL,
+ .fail_domain_create = NULL,
+ .post_domain_destroy = ste_post_domain_destroy,
+ /* event channel control hooks */
+ .pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
+ .fail_eventchannel_unbound = NULL,
+ .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
+ .fail_eventchannel_interdomain = NULL,
+ /* grant table control hooks */
+ .pre_grant_map_ref = ste_pre_grant_map_ref,
+ .fail_grant_map_ref = NULL,
+ .pre_grant_setup = ste_pre_grant_setup,
+ .fail_grant_setup = NULL,
+};
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index b0ebecfcee..ca7cf17aca 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -20,6 +20,7 @@
#include <asm/desc.h>
#include <asm/shadow.h>
#include <asm/e820.h>
+#include <public/acm_dom0_setup.h>
extern void dmi_scan_machine(void);
extern void generic_apic_probe(void);
@@ -393,12 +394,17 @@ void __init __start_xen(multiboot_info_t *mbi)
shadow_mode_init();
+ /* initialize access control security module */
+ acm_init();
+
/* Create initial domain 0. */
dom0 = do_createdomain(0, 0);
if ( dom0 == NULL )
panic("Error creating domain 0\n");
set_bit(_DOMF_privileged, &dom0->domain_flags);
+ /* post-create hooks sets security label */
+ acm_post_domain0_create(dom0->domain_id);
/* Grab the DOM0 command line. */
cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index 475474b99a..93827336d4 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -751,6 +751,7 @@ ENTRY(hypercall_table)
.long do_boot_vcpu
.long do_ni_hypercall /* 25 */
.long do_mmuext_op
+ .long do_policy_op /* 27 */
.rept NR_hypercalls-((.-hypercall_table)/4)
.long do_ni_hypercall
.endr
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index 8b3dd1edbc..ec86fc1b62 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -19,6 +19,7 @@
#include <asm/current.h>
#include <public/dom0_ops.h>
#include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
extern void arch_getdomaininfo_ctxt(
@@ -91,6 +92,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
{
long ret = 0;
dom0_op_t curop, *op = &curop;
+ void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
if ( !IS_PRIV(current->domain) )
return -EPERM;
@@ -101,6 +103,9 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( op->interface_version != DOM0_INTERFACE_VERSION )
return -EACCES;
+ if ( acm_pre_dom0_op(op, &ssid) )
+ return -EACCES;
+
switch ( op->cmd )
{
@@ -357,6 +362,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
+ if (d->ssid != NULL)
+ op->u.getdomaininfo.ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
+ else
+ op->u.getdomaininfo.ssidref = ACM_DEFAULT_SSID;
+
op->u.getdomaininfo.tot_pages = d->tot_pages;
op->u.getdomaininfo.max_pages = d->max_pages;
op->u.getdomaininfo.shared_info_frame =
@@ -493,7 +503,10 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
ret = arch_do_dom0_op(op,u_dom0_op);
}
-
+ if (!ret)
+ acm_post_dom0_op(op, ssid);
+ else
+ acm_fail_dom0_op(op, ssid);
return ret;
}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 6f6e707667..29d10ef3d2 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -26,6 +26,7 @@
#include <public/xen.h>
#include <public/event_channel.h>
+#include <acm/acm_hooks.h>
#define bucket_from_port(d,p) \
((d)->evtchn[(p)/EVTCHNS_PER_BUCKET])
@@ -587,6 +588,9 @@ long do_event_channel_op(evtchn_op_t *uop)
if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
return -EFAULT;
+ if (acm_pre_event_channel(&op))
+ return -EACCES;
+
switch ( op.cmd )
{
case EVTCHNOP_alloc_unbound:
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 683a051df3..9e7b7223e9 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -30,6 +30,7 @@
#include <xen/sched.h>
#include <xen/shadow.h>
#include <xen/mm.h>
+#include <acm/acm_hooks.h>
#define PIN_FAIL(_lbl, _rc, _f, _a...) \
do { \
@@ -357,6 +358,11 @@ __gnttab_map_grant_ref(
return GNTST_bad_gntref;
}
+ if (acm_pre_grant_map_ref(dom)) {
+ (void)__put_user(GNTST_permission_denied, &uop->handle);
+ return GNTST_permission_denied;
+ }
+
if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
unlikely(ld == rd) )
{
diff --git a/xen/common/policy_ops.c b/xen/common/policy_ops.c
new file mode 100644
index 0000000000..ff2b2f9ba4
--- /dev/null
+++ b/xen/common/policy_ops.c
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *policy_ops.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * Process policy command requests from guest OS.
+ *
+ */
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <public/policy_ops.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/trace.h>
+#include <xen/console.h>
+#include <asm/shadow.h>
+#include <public/sched_ctl.h>
+#include <acm/acm_hooks.h>
+
+/* function prototypes defined in acm/acm_policy.c */
+int acm_set_policy(void *buf, u16 buf_size, u16 policy);
+int acm_get_policy(void *buf, u16 buf_size);
+int acm_dump_statistics(void *buf, u16 buf_size);
+
+typedef enum policyoperation {
+ POLICY, /* access to policy interface (early drop) */
+ GETPOLICY, /* dump policy cache */
+ SETPOLICY, /* set policy cache (controls security) */
+ DUMPSTATS /* dump policy statistics */
+} policyoperation_t;
+
+int
+acm_authorize_policyops(struct domain *d, policyoperation_t pops)
+{
+ /* currently, all policy management functions are restricted to privileged domains,
+ * soon we will introduce finer-grained privileges for policy operations
+ */
+ if (!IS_PRIV(d)) {
+ printk("%s: Policy management authorization denied ERROR!\n", __func__);
+ return ACM_ACCESS_DENIED;
+ }
+ return ACM_ACCESS_PERMITTED;
+}
+
+long do_policy_op(policy_op_t *u_policy_op)
+{
+ long ret = 0;
+ policy_op_t curop, *op = &curop;
+
+ /* check here policy decision for policy commands */
+ /* for now allow DOM0 only, later indepedently */
+ if (acm_authorize_policyops(current->domain, POLICY))
+ return -EACCES;
+
+ if ( copy_from_user(op, u_policy_op, sizeof(*op)) )
+ return -EFAULT;
+
+ if ( op->interface_version != POLICY_INTERFACE_VERSION )
+ return -EACCES;
+
+ switch ( op->cmd )
+ {
+ case POLICY_SETPOLICY:
+ {
+ if (acm_authorize_policyops(current->domain, SETPOLICY))
+ return -EACCES;
+ printkd("%s: setting policy.\n", __func__);
+ ret = acm_set_policy(op->u.setpolicy.pushcache, op->u.setpolicy.pushcache_size, op->u.setpolicy.policy_type);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ case POLICY_GETPOLICY:
+ {
+ if (acm_authorize_policyops(current->domain, GETPOLICY))
+ return -EACCES;
+ printkd("%s: getting policy.\n", __func__);
+ ret = acm_get_policy(op->u.getpolicy.pullcache, op->u.getpolicy.pullcache_size);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ case POLICY_DUMPSTATS:
+ {
+ if (acm_authorize_policyops(current->domain, DUMPSTATS))
+ return -EACCES;
+ printkd("%s: dumping statistics.\n", __func__);
+ ret = acm_dump_statistics(op->u.dumpstats.pullcache, op->u.dumpstats.pullcache_size);
+ if (ret == ACM_OK)
+ ret = 0;
+ else
+ ret = -ESRCH;
+ }
+ break;
+
+ default:
+ ret = -ESRCH;
+
+ }
+ return ret;
+}
diff --git a/xen/include/acm/acm_core.h b/xen/include/acm/acm_core.h
new file mode 100644
index 0000000000..e404b455ad
--- /dev/null
+++ b/xen/include/acm/acm_core.h
@@ -0,0 +1,117 @@
+/****************************************************************
+ * acm_core.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * sHype header file describing core data types and constants
+ * for the access control module and relevant policies
+ *
+ */
+#ifndef _ACM_CORE_H
+#define _ACM_CORE_H
+
+#include <xen/spinlock.h>
+#include <public/acm.h>
+#include <public/policy_ops.h>
+
+/* Xen-internal representation of the binary policy */
+struct acm_binary_policy {
+ u16 primary_policy_code;
+ u16 secondary_policy_code;
+ void *primary_binary_policy;
+ void *secondary_binary_policy;
+
+};
+
+struct chwall_binary_policy {
+ u16 max_types;
+ u16 max_ssidrefs;
+ u16 max_conflictsets;
+ domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
+ domaintype_t *conflict_aggregate_set; /* [max_types] */
+ domaintype_t *running_types; /* [max_types] */
+ domaintype_t *conflict_sets; /* [max_conflictsets][max_types]*/
+};
+
+struct ste_binary_policy {
+ u16 max_types;
+ u16 max_ssidrefs;
+ domaintype_t *ssidrefs; /* [max_ssidrefs][max_types] */
+ atomic_t ec_eval_count, gt_eval_count;
+ atomic_t ec_denied_count, gt_denied_count;
+ atomic_t ec_cachehit_count, gt_cachehit_count;
+};
+
+/* global acm policy */
+extern struct acm_binary_policy acm_bin_pol;
+extern struct chwall_binary_policy chwall_bin_pol;
+extern struct ste_binary_policy ste_bin_pol;
+/* use the lock when reading / changing binary policy ! */
+extern rwlock_t acm_bin_pol_rwlock;
+
+/* subject and object type definitions */
+enum acm_datatype { DOMAIN };
+
+/* defines number of access decisions to other domains can be cached
+ * one entry per domain, TE does not distinguish evtchn or grant_table */
+#define ACM_TE_CACHE_SIZE 8
+enum acm_ste_flag { VALID, FREE };
+
+/* cache line:
+ * if cache_line.valid==VALID, then
+ * STE decision is cached as "permitted"
+ * on domain cache_line.id
+ */
+struct acm_ste_cache_line {
+ enum acm_ste_flag valid;
+ domid_t id;
+};
+
+/* general definition of a subject security id */
+struct acm_ssid_domain {
+ enum acm_datatype datatype; /* type of subject (e.g., partition) */
+ ssidref_t ssidref; /* combined security reference */
+ void *primary_ssid; /* primary policy ssid part (e.g. chinese wall) */
+ void *secondary_ssid; /* secondary policy ssid part (e.g. type enforcement) */
+ struct domain *subject; /* backpointer to subject structure */
+ domid_t domainid; /* replicate id */
+};
+
+/* chinese wall ssid type */
+struct chwall_ssid {
+ ssidref_t chwall_ssidref;
+};
+
+/* simple type enforcement ssid type */
+struct ste_ssid {
+ ssidref_t ste_ssidref;
+ struct acm_ste_cache_line ste_cache[ACM_TE_CACHE_SIZE]; /* decision cache */
+};
+
+/* macros to access ssidref for primary / secondary policy
+ * primary ssidref = lower 16 bit
+ * secondary ssidref = higher 16 bit
+ */
+#define GET_SSIDREF(POLICY, ssidref) \
+ ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+ ((ssidref) & 0xffff) : ((ssidref) >> 16)
+
+/* macros to access ssid pointer for primary / secondary policy */
+#define GET_SSIDP(POLICY, ssid) \
+ ((POLICY) == acm_bin_pol.primary_policy_code) ? \
+ ((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
+
+/* protos */
+int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
+int acm_free_domain_ssid(struct acm_ssid_domain *ssid);
+
+#endif
+
diff --git a/xen/include/acm/acm_endian.h b/xen/include/acm/acm_endian.h
new file mode 100644
index 0000000000..fd7229b846
--- /dev/null
+++ b/xen/include/acm/acm_endian.h
@@ -0,0 +1,88 @@
+/****************************************************************
+ * acm_endian.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ *
+ * Contributions:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * sHype header file defining endian-dependent functions for the
+ * big-endian policy interface
+ *
+ */
+#ifndef _ACM_ENDIAN_H
+#define _ACM_ENDIAN_H
+
+/* don't use these functions in performance critical sections! */
+
+/* set during initialization by testing */
+extern u8 little_endian;
+
+static inline u32 ntohl(u32 x)
+{
+ if (little_endian)
+ return
+ ( (((x) >> 24) & 0xff )|
+ (((x) >> 8) & 0xff00 )|
+ (((x) << 8) & 0xff0000 )|
+ (((x) << 24) & 0xff000000) );
+ else
+ return x;
+}
+
+static inline u16 ntohs(u16 x)
+{
+ if (little_endian)
+ return
+ ( (((x) >> 8) & 0xff )|
+ (((x) << 8) & 0xff00 ) );
+ else
+ return x;
+}
+
+#define htonl(x) ntohl(x)
+#define htons(x) ntohs(x)
+
+static inline void arrcpy16(u16 *dest, const u16 *src, size_t n)
+{
+ unsigned int i = 0;
+ while (i < n) {
+ dest[i] = htons(src[i]);
+ i++;
+ }
+}
+
+static inline void arrcpy32(u32 *dest, const u32 *src, size_t n)
+{
+ unsigned int i = 0;
+ while (i < n) {
+ dest[i] = htonl(src[i]);
+ i++;
+ }
+}
+
+static inline void arrcpy(void *dest, const void *src, unsigned int elsize, size_t n)
+{
+ switch (elsize) {
+ case sizeof(u16):
+ arrcpy16((u16 *)dest, (u16 *)src, n);
+ break;
+
+ case sizeof(u32):
+ arrcpy32((u32 *)dest, (u32 *)src, n);
+ break;
+
+ default:
+ memcpy(dest, src, elsize*n);
+ }
+}
+
+#endif
diff --git a/xen/include/acm/acm_hooks.h b/xen/include/acm/acm_hooks.h
new file mode 100644
index 0000000000..534d919ff4
--- /dev/null
+++ b/xen/include/acm/acm_hooks.h
@@ -0,0 +1,337 @@
+/****************************************************************
+ * acm_hooks.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * acm header file implementing the global (policy-independent)
+ * sHype hooks that are called throughout Xen.
+ *
+ */
+#ifndef _ACM_HOOKS_H
+#define _ACM_HOOKS_H
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/delay.h>
+#include <xen/sched.h>
+#include <public/acm.h>
+#include <acm/acm_core.h>
+#include <public/dom0_ops.h>
+#include <public/event_channel.h>
+#include <asm/current.h>
+
+/* if ACM_TRACE_MODE defined, all hooks should
+ * print a short trace message */
+/* #define ACM_TRACE_MODE */
+
+#ifdef ACM_TRACE_MODE
+# define traceprintk(fmt, args...) printk(fmt,## args)
+#else
+# define traceprintk(fmt, args...)
+#endif
+
+/* global variables */
+extern struct acm_operations *acm_primary_ops;
+extern struct acm_operations *acm_secondary_ops;
+
+/**********************************************************************************************
+ * HOOK structure and meaning (justifies a few words about our model):
+ *
+ * General idea: every policy-controlled system operation is reflected in a
+ * transaction in the system's security state
+ *
+ * Keeping the security state consistent requires "atomic" transactions.
+ * The name of the hooks to place around policy-controlled transactions
+ * reflects this. If authorizations do not involve security state changes,
+ * then and only then POST and FAIL hooks remain empty since we don't care
+ * about the eventual outcome of the operation from a security viewpoint.
+ *
+ * PURPOSE of hook types:
+ * ======================
+ * PRE-Hooks
+ * a) general authorization to guard a controlled system operation
+ * b) prepare security state change (means: fail hook must be able to "undo" this)
+ *
+ * POST-Hooks
+ * a) commit prepared state change
+ *
+ * FAIL-Hooks
+ * a) roll-back prepared security state change from PRE-Hook
+ *
+ *
+ * PLACEMENT of hook types:
+ * ========================
+ * PRE-Hooks must be called:
+ * a) before a guarded/controlled system operation is started
+ * (return is ACM_ACCESS_PERMITTED or ACM_ACCESS_DENIED or error)
+ * --> operation must be aborted if return is != ACM_ACCESS_PERMITTED
+ *
+ * POST-Hooks must be called:
+ * a) after successful transaction (no return value; commit shall never fail)
+ *
+ * FAIL-Hooks must be called:
+ * a) if system transaction (operation) fails somewhen after calling the PRE-hook
+ * (obviously the POST-Hook is not called in this case)
+ * b) if another (secondary) policy denies access in its PRE-Hook
+ * (policy layering is useful but requires additional handling)
+ *
+ *
+ *
+ * Hook model from a security transaction viewpoint:
+ *
+ * start-sys-ops--> prepare ----succeed-----> commit --> sys-ops success
+ * (pre-hook) \ (post-hook)
+ * \
+ * fail
+ * \
+ * \
+ * roll-back
+ * (fail-hook)
+ * \
+ * sys-ops error
+ *
+ *************************************************************************************************/
+
+struct acm_operations {
+ /* policy management functions (must always be defined!) */
+ int (*init_domain_ssid) (void **ssid, ssidref_t ssidref);
+ void (*free_domain_ssid) (void *ssid);
+ int (*dump_binary_policy) (u8 *buffer, u16 buf_size);
+ int (*set_binary_policy) (u8 *buffer, u16 buf_size);
+ int (*dump_statistics) (u8 *buffer, u16 buf_size);
+ /* domain management control hooks (can be NULL) */
+ int (*pre_domain_create) (void *subject_ssid, ssidref_t ssidref);
+ void (*post_domain_create) (domid_t domid, ssidref_t ssidref);
+ void (*fail_domain_create) (void *subject_ssid, ssidref_t ssidref);
+ void (*post_domain_destroy) (void *object_ssid, domid_t id);
+ /* event channel control hooks (can be NULL) */
+ int (*pre_eventchannel_unbound) (domid_t id);
+ void (*fail_eventchannel_unbound) (domid_t id);
+ int (*pre_eventchannel_interdomain) (domid_t id1, domid_t id2);
+ int (*fail_eventchannel_interdomain) (domid_t id1, domid_t id2);
+ /* grant table control hooks (can be NULL) */
+ int (*pre_grant_map_ref) (domid_t id);
+ void (*fail_grant_map_ref) (domid_t id);
+ int (*pre_grant_setup) (domid_t id);
+ void (*fail_grant_setup) (domid_t id);
+};
+
+static inline int acm_pre_domain_create (void *subject_ssid, ssidref_t ssidref)
+{
+ if ((acm_primary_ops->pre_domain_create != NULL) &&
+ acm_primary_ops->pre_domain_create (subject_ssid, ssidref))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_domain_create != NULL) &&
+ acm_secondary_ops->pre_domain_create (subject_ssid, ssidref)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_domain_create != NULL)
+ acm_primary_ops->fail_domain_create (subject_ssid, ssidref);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static inline void acm_post_domain_create (domid_t domid, ssidref_t ssidref)
+{
+ if (acm_primary_ops->post_domain_create != NULL)
+ acm_primary_ops->post_domain_create (domid, ssidref);
+ if (acm_secondary_ops->post_domain_create != NULL)
+ acm_secondary_ops->post_domain_create (domid, ssidref);
+}
+
+static inline void acm_fail_domain_create (void *subject_ssid, ssidref_t ssidref)
+{
+ if (acm_primary_ops->fail_domain_create != NULL)
+ acm_primary_ops->fail_domain_create (subject_ssid, ssidref);
+ if (acm_secondary_ops->fail_domain_create != NULL)
+ acm_secondary_ops->fail_domain_create (subject_ssid, ssidref);
+}
+
+static inline void acm_post_domain_destroy (void *object_ssid, domid_t id)
+{
+ if (acm_primary_ops->post_domain_destroy != NULL)
+ acm_primary_ops->post_domain_destroy (object_ssid, id);
+ if (acm_secondary_ops->post_domain_destroy != NULL)
+ acm_secondary_ops->post_domain_destroy (object_ssid, id);
+ return;
+}
+
+/* event channel ops */
+
+static inline int acm_pre_eventchannel_unbound (domid_t id)
+{
+ if ((acm_primary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_primary_ops->pre_eventchannel_unbound (id))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_unbound != NULL) &&
+ acm_secondary_ops->pre_eventchannel_unbound (id)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_unbound != NULL)
+ acm_primary_ops->fail_eventchannel_unbound (id);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+static inline int acm_pre_eventchannel_interdomain (domid_t id1, domid_t id2)
+{
+ if ((acm_primary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_primary_ops->pre_eventchannel_interdomain (id1, id2))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_eventchannel_interdomain != NULL) &&
+ acm_secondary_ops->pre_eventchannel_interdomain (id1, id2)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_eventchannel_interdomain != NULL)
+ acm_primary_ops->fail_eventchannel_interdomain (id1, id2);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+
+/************ Xen inline hooks ***************/
+
+/* small macro to make the hooks more readable
+ * (eliminates hooks if NULL policy is active)
+ */
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
+{ return 0; }
+#else
+static inline int acm_pre_dom0_op(dom0_op_t *op, void **ssid)
+{
+ int ret = -EACCES;
+ struct domain *d;
+
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ ret = acm_pre_domain_create(current->domain->ssid, op->u.createdomain.ssidref);
+ break;
+ case DOM0_DESTROYDOMAIN:
+ d = find_domain_by_id(op->u.destroydomain.domain);
+ if (d != NULL) {
+ *ssid = d->ssid; /* save for post destroy when d is gone */
+ /* no policy-specific hook */
+ put_domain(d);
+ ret = 0;
+ }
+ break;
+ default:
+ ret = 0; /* ok */
+ }
+ return ret;
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid)
+{ return; }
+#else
+static inline void acm_post_dom0_op(dom0_op_t *op, void *ssid)
+{
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ /* initialialize shared sHype security labels for new domain */
+ acm_init_domain_ssid(op->u.createdomain.domain, op->u.createdomain.ssidref);
+ acm_post_domain_create(op->u.createdomain.domain, op->u.createdomain.ssidref);
+ break;
+ case DOM0_DESTROYDOMAIN:
+ acm_post_domain_destroy(ssid, op->u.destroydomain.domain);
+ /* free security ssid for the destroyed domain (also if running null policy */
+ acm_free_domain_ssid((struct acm_ssid_domain *)ssid);
+ break;
+ }
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICy == ACM_NULL_POLICY)
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid)
+{ return; }
+#else
+static inline void acm_fail_dom0_op(dom0_op_t *op, void *ssid)
+{
+ switch(op->cmd) {
+ case DOM0_CREATEDOMAIN:
+ acm_fail_domain_create(current->domain->ssid, op->u.createdomain.ssidref);
+ break;
+ }
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_event_channel(evtchn_op_t *op)
+{ return 0; }
+#else
+static inline int acm_pre_event_channel(evtchn_op_t *op)
+{
+ int ret = -EACCES;
+
+ switch(op->cmd) {
+ case EVTCHNOP_alloc_unbound:
+ ret = acm_pre_eventchannel_unbound(op->u.alloc_unbound.dom);
+ break;
+ case EVTCHNOP_bind_interdomain:
+ ret = acm_pre_eventchannel_interdomain(op->u.bind_interdomain.dom1, op->u.bind_interdomain.dom2);
+ break;
+ default:
+ ret = 0; /* ok */
+ }
+ return ret;
+}
+#endif
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_grant_map_ref(domid_t id)
+{ return 0; }
+#else
+static inline int acm_pre_grant_map_ref (domid_t id)
+{
+ if ((acm_primary_ops->pre_grant_map_ref != NULL) &&
+ acm_primary_ops->pre_grant_map_ref (id))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_grant_map_ref != NULL) &&
+ acm_secondary_ops->pre_grant_map_ref (id)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_grant_map_ref != NULL)
+ acm_primary_ops->fail_grant_map_ref (id);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+#endif
+
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+static inline int acm_pre_grant_setup(domid_t id)
+{ return 0; }
+#else
+static inline int acm_pre_grant_setup (domid_t id)
+{
+ if ((acm_primary_ops->pre_grant_setup != NULL) &&
+ acm_primary_ops->pre_grant_setup (id))
+ return ACM_ACCESS_DENIED;
+ else if ((acm_secondary_ops->pre_grant_setup != NULL) &&
+ acm_secondary_ops->pre_grant_setup (id)) {
+ /* roll-back primary */
+ if (acm_primary_ops->fail_grant_setup != NULL)
+ acm_primary_ops->fail_grant_setup (id);
+ return ACM_ACCESS_DENIED;
+ } else
+ return ACM_ACCESS_PERMITTED;
+}
+#endif
+
+
+#endif
diff --git a/xen/include/public/acm.h b/xen/include/public/acm.h
new file mode 100644
index 0000000000..31191b7b5a
--- /dev/null
+++ b/xen/include/public/acm.h
@@ -0,0 +1,161 @@
+/****************************************************************
+ * acm.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Contributors:
+ * Stefan Berger <stefanb@watson.ibm.com>
+ * added network byte order support for binary policies
+ *
+ * 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 of the
+ * License.
+ *
+ * sHype general access control module header file.
+ * here are all definitions that are shared between
+ * xen-core, guest-kernels, and applications.
+ *
+ * todo: move from static policy choice to compile option.
+ */
+
+#ifndef _XEN_PUBLIC_SHYPE_H
+#define _XEN_PUBLIC_SHYPE_H
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/* if ACM_DEBUG defined, all hooks should
+ * print a short trace message (comment it out
+ * when not in testing mode )
+ */
+/* #define ACM_DEBUG */
+
+#ifdef ACM_DEBUG
+# define printkd(fmt, args...) printk(fmt,## args)
+#else
+# define printkd(fmt, args...)
+#endif
+
+/* default ssid reference value if not supplied */
+#define ACM_DEFAULT_SSID 0xffffffff
+#define ACM_DEFAULT_LOCAL_SSID 0xffff
+
+/* Internal ACM ERROR types */
+#define ACM_OK 0
+#define ACM_UNDEF -1
+#define ACM_INIT_SSID_ERROR -2
+#define ACM_INIT_SOID_ERROR -3
+#define ACM_ERROR -4
+
+/* External ACCESS DECISIONS */
+#define ACM_ACCESS_PERMITTED 0
+#define ACM_ACCESS_DENIED -111
+#define ACM_NULL_POINTER_ERROR -200
+
+#define ACM_MAX_POLICY 3
+
+#define ACM_NULL_POLICY 0
+#define ACM_CHINESE_WALL_POLICY 1
+#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2
+#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY 3
+
+/* policy: */
+#define ACM_POLICY_NAME(X) \
+ (X == ACM_NULL_POLICY) ? "NULL policy" : \
+ (X == ACM_CHINESE_WALL_POLICY) ? "CHINESE WALL policy" : \
+ (X == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "SIMPLE TYPE ENFORCEMENT policy" : \
+ (X == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT policy" : \
+ "UNDEFINED policy"
+
+#ifndef ACM_USE_SECURITY_POLICY
+#define ACM_USE_SECURITY_POLICY ACM_NULL_POLICY
+#endif
+
+/* defines a ssid reference used by xen */
+typedef u32 ssidref_t;
+
+/* -------security policy relevant type definitions-------- */
+
+/* type identifier; compares to "equal" or "not equal" */
+typedef u16 domaintype_t;
+
+/* CHINESE WALL POLICY DATA STRUCTURES
+ *
+ * current accumulated conflict type set:
+ * When a domain is started and has a type that is in
+ * a conflict set, the conflicting types are incremented in
+ * the aggregate set. When a domain is destroyed, the
+ * conflicting types to its type are decremented.
+ * If a domain has multiple types, this procedure works over
+ * all those types.
+ *
+ * conflict_aggregate_set[i] holds the number of
+ * running domains that have a conflict with type i.
+ *
+ * running_types[i] holds the number of running domains
+ * that include type i in their ssidref-referenced type set
+ *
+ * conflict_sets[i][j] is "0" if type j has no conflict
+ * with type i and is "1" otherwise.
+ */
+/* high-16 = version, low-16 = check magic */
+#define ACM_MAGIC 0x0001debc
+
+/* each offset in bytes from start of the struct they
+ * the are part of */
+/* each buffer consists of all policy information for
+ * the respective policy given in the policy code
+ */
+struct acm_policy_buffer {
+ u32 magic;
+ u32 policyversion;
+ u32 len;
+ u16 primary_policy_code;
+ u16 primary_buffer_offset;
+ u16 secondary_policy_code;
+ u16 secondary_buffer_offset;
+};
+
+struct acm_chwall_policy_buffer {
+ u16 policy_code;
+ u16 chwall_max_types;
+ u16 chwall_max_ssidrefs;
+ u16 chwall_max_conflictsets;
+ u16 chwall_ssid_offset;
+ u16 chwall_conflict_sets_offset;
+ u16 chwall_running_types_offset;
+ u16 chwall_conflict_aggregate_offset;
+};
+
+struct acm_ste_policy_buffer {
+ u16 policy_code;
+ u16 ste_max_types;
+ u16 ste_max_ssidrefs;
+ u16 ste_ssid_offset;
+};
+
+struct acm_stats_buffer {
+ u32 magic;
+ u32 policyversion;
+ u32 len;
+ u16 primary_policy_code;
+ u16 primary_stats_offset;
+ u16 secondary_policy_code;
+ u16 secondary_stats_offset;
+};
+
+struct acm_ste_stats_buffer {
+ u32 ec_eval_count;
+ u32 gt_eval_count;
+ u32 ec_denied_count;
+ u32 gt_denied_count;
+ u32 ec_cachehit_count;
+ u32 gt_cachehit_count;
+};
+
+
+#endif
diff --git a/xen/include/public/acm_dom0_setup.h b/xen/include/public/acm_dom0_setup.h
new file mode 100644
index 0000000000..6604156ccf
--- /dev/null
+++ b/xen/include/public/acm_dom0_setup.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ * acm_dom0_setup.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.com>
+ *
+ * Includes necessary definitions to bring-up dom0
+ */
+#include <acm/acm_hooks.h>
+
+extern int acm_init(void);
+
+#if (ACM_USE_SECURITY_POLICY == ACM_NULL_POLICY)
+
+static inline void acm_post_domain0_create(domid_t domid)
+{
+ return;
+}
+
+#else
+
+/* predefined ssidref for DOM0 used by xen when creating DOM0 */
+#define ACM_DOM0_SSIDREF 0
+
+static inline void acm_post_domain0_create(domid_t domid)
+{
+ /* initialialize shared sHype security labels for new domain */
+ acm_init_domain_ssid(domid, ACM_DOM0_SSIDREF);
+ acm_post_domain_create(domid, ACM_DOM0_SSIDREF);
+}
+
+#endif
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index 0768b8c6ae..3ff82b43ac 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -43,6 +43,8 @@ typedef struct sched_adjdom_cmd dom0_adjustdom_t;
#define DOM0_CREATEDOMAIN 8
typedef struct {
+ /* IN parameters */
+ u32 ssidref;
/* IN/OUT parameters. */
/* Identifier for new domain (auto-allocate if zero is specified). */
domid_t domain;
@@ -88,6 +90,7 @@ typedef struct {
u32 n_vcpu;
s32 vcpu_to_cpu[MAX_VIRT_CPUS]; /* current mapping */
cpumap_t cpumap[MAX_VIRT_CPUS]; /* allowable mapping */
+ u32 ssidref;
} dom0_getdomaininfo_t;
#define DOM0_SETDOMAININFO 13
diff --git a/xen/include/public/policy_ops.h b/xen/include/public/policy_ops.h
new file mode 100644
index 0000000000..6b55f764b1
--- /dev/null
+++ b/xen/include/public/policy_ops.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * policy_ops.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Author:
+ * Reiner Sailer <sailer@watson.ibm.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 of the
+ * License.
+ *
+ * Process policy command requests from guest OS.
+ * access checked by policy; not restricted to DOM0
+ *
+ */
+
+
+#ifndef __XEN_PUBLIC_POLICY_OPS_H__
+#define __XEN_PUBLIC_POLICY_OPS_H__
+
+#include "xen.h"
+#include "sched_ctl.h"
+
+/*
+ * Make sure you increment the interface version whenever you modify this file!
+ * This makes sure that old versions of policy tools will stop working in a
+ * well-defined way (rather than crashing the machine, for instance).
+ */
+#define POLICY_INTERFACE_VERSION 0xAAAA0001
+
+/************************************************************************/
+
+#define POLICY_SETPOLICY 4
+typedef struct {
+ /* IN variables. */
+ u16 policy_type;
+ u16 padding1;
+ /* OUT variables */
+ void *pushcache;
+ u16 pushcache_size;
+} PACKED policy_setpolicy_t;
+
+
+#define POLICY_GETPOLICY 5
+typedef struct {
+ /* IN variables. */
+ u16 policy_type;
+ u16 padding1;
+ /* OUT variables */
+ void *pullcache;
+ u16 pullcache_size;
+} PACKED policy_getpolicy_t;
+
+#define POLICY_DUMPSTATS 6
+typedef struct {
+ void *pullcache;
+ u16 pullcache_size;
+} PACKED policy_dumpstats_t;
+
+
+typedef struct {
+ u32 cmd; /* 0 */
+ u32 interface_version; /* 4 */ /* POLICY_INTERFACE_VERSION */
+ union { /* 8 */
+ u32 dummy[14]; /* 72bytes */
+ policy_setpolicy_t setpolicy;
+ policy_getpolicy_t getpolicy;
+ policy_dumpstats_t dumpstats;
+ } PACKED u;
+} PACKED policy_op_t; /* 80 bytes */
+
+#endif /* __XEN_PUBLIC_POLICY_OPS_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 2fdd400e92..8b183491a6 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -58,6 +58,7 @@
#define __HYPERVISOR_boot_vcpu 24
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
#define __HYPERVISOR_mmuext_op 26
+#define __HYPERVISOR_policy_op 27
/*
* VIRTUAL INTERRUPTS
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 35a3c36cab..7649f1a450 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -137,6 +137,8 @@ struct domain
cpumask_t cpumask;
struct arch_domain arch;
+
+ void *ssid; /* sHype security subject identifier */
};
struct domain_setup_info