Mailing List Archive

[xen-unstable] Xen Security Modules: Tools.
# HG changeset patch
# User kfraser@localhost.localdomain
# Date 1188556640 -3600
# Node ID 993655d24b5502c56e27c9f52498934b2d528ff9
# Parent 6c8c934b235c39f821efdfe6a2af7d44e4e35aab
Xen Security Modules: Tools.
Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
---
tools/Makefile | 3
tools/flask/Makefile | 26
tools/flask/libflask/Makefile | 65 +
tools/flask/libflask/flask_op.c | 100 ++
tools/flask/libflask/include/flask_op.h | 46 +
tools/flask/loadpolicy/Makefile | 61 +
tools/flask/loadpolicy/loadpolicy.c | 130 ++
tools/misc/xenperf.c | 2
tools/python/Makefile | 26
tools/python/setup.py | 19
tools/python/xen/lowlevel/flask/flask.c | 139 +++
tools/python/xen/util/acmpolicy.py | 9
tools/python/xen/util/xsm/__init__.py | 2
tools/python/xen/util/xsm/acm/__init__.py | 1
tools/python/xen/util/xsm/acm/acm.py | 1283 ++++++++++++++++++++++++++++
tools/python/xen/util/xsm/dummy/__init__.py | 1
tools/python/xen/util/xsm/dummy/dummy.py | 53 +
tools/python/xen/util/xsm/flask/__init__.py | 1
tools/python/xen/util/xsm/flask/flask.py | 37
tools/python/xen/util/xsm/xsm_core.py | 7
tools/python/xen/xend/XendConfig.py | 12
tools/python/xen/xend/XendDomainInfo.py | 2
tools/python/xen/xend/XendVDI.py | 3
tools/python/xen/xend/XendXSPolicy.py | 3
tools/python/xen/xend/XendXSPolicyAdmin.py | 3
tools/python/xen/xend/server/blkif.py | 2
tools/python/xen/xend/server/netif.py | 2
tools/python/xen/xm/addlabel.py | 2
tools/python/xen/xm/cfgbootpolicy.py | 10
tools/python/xen/xm/create.py | 8
tools/python/xen/xm/dry-run.py | 2
tools/python/xen/xm/dumppolicy.py | 2
tools/python/xen/xm/getlabel.py | 6
tools/python/xen/xm/labels.py | 6
tools/python/xen/xm/loadpolicy.py | 2
tools/python/xen/xm/main.py | 28
tools/python/xen/xm/makepolicy.py | 2
tools/python/xen/xm/resources.py | 2
tools/python/xen/xm/rmlabel.py | 4
tools/python/xen/xm/setpolicy.py | 2
40 files changed, 2053 insertions(+), 61 deletions(-)

diff -r 6c8c934b235c -r 993655d24b55 tools/Makefile
--- a/tools/Makefile Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/Makefile Fri Aug 31 11:37:20 2007 +0100
@@ -3,6 +3,9 @@ include $(XEN_ROOT)/tools/Rules.mk

SUBDIRS-y :=
SUBDIRS-y += libxc
+ifeq ($(FLASK_ENABLE),y)
+SUBDIRS-y += flask
+endif
SUBDIRS-y += xenstore
SUBDIRS-y += misc
SUBDIRS-y += examples
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/Makefile Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,26 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SUBDIRS :=
+SUBDIRS += libflask
+SUBDIRS += loadpolicy
+
+.PHONY: all
+all:
+ @set -e; for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $@; \
+ done
+
+.PHONY: install
+install:
+ @set -e; for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $@; \
+ done
+
+.PHONY: clean
+clean:
+ @set -e; for subdir in $(SUBDIRS); do \
+ $(MAKE) -C $$subdir $@; \
+ done
+
+
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/libflask/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/Makefile Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,65 @@
+MAJOR = 1.0
+MINOR = 0
+
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+XEN_LIBXC = $(XEN_ROOT)/tools/libxc
+
+SRCS :=
+SRCS += flask_op.c
+
+CFLAGS += -Werror
+CFLAGS += -fno-strict-aliasing
+CFLAGS += $(INCLUDES) -I./include -I$(XEN_LIBXC)
+
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+LDFLAGS += -L.
+DEPS = .*.d
+
+LIB_OBJS := $(patsubst %.c,%.o,$(SRCS))
+PIC_OBJS := $(patsubst %.c,%.opic,$(SRCS))
+
+LIB := libflask.a
+LIB += libflask.so libflask.so.$(MAJOR) libflask.so.$(MAJOR).$(MINOR)
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build:
+ $(MAKE) $(LIB)
+
+.PHONY: install
+install: build
+ [ -d $(DESTDIR)/usr/$(LIBDIR) ] || $(INSTALL_DIR) $(DESTDIR)/usr/$(LIBDIR)
+ [ -d $(DESTDIR)/usr/include ] || $(INSTALL_DIR) $(DESTDIR)/usr/include
+ $(INSTALL_PROG) libflask.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)
+ $(INSTALL_DATA) libflask.a $(DESTDIR)/usr/$(LIBDIR)
+ ln -sf libflask.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)/libflask.so.$(MAJOR)
+ ln -sf libflask.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libflask.so
+ $(INSTALL_DATA) include/flask_op.h $(DESTDIR)/usr/include
+
+.PHONY: TAGS
+TAGS:
+ etags -t *.c *.h
+
+.PHONY: clean
+clean:
+ rm -rf *.a *.so* *.o *.opic *.rpm $(LIB) *~ $(DEPS) xen
+
+# libflask
+
+libflask.a: $(LIB_OBJS)
+ $(AR) rc $@ $^
+
+libflask.so: libflask.so.$(MAJOR)
+ ln -sf $< $@
+libflask.so.$(MAJOR): libflask.so.$(MAJOR).$(MINOR)
+ ln -sf $< $@
+
+libflask.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libflask.so.$(MAJOR) -shared -o $@ $^
+
+-include $(DEPS)
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/libflask/flask_op.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/flask_op.c Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,100 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <xc_private.h>
+
+#include <flask_op.h>
+
+int flask_load(int xc_handle, char *buf, int size)
+{
+ int err;
+ flask_op_t op;
+
+ op.cmd = FLASK_LOAD;
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = do_flask_op(xc_handle, &op)) != 0 )
+ return err;
+
+ return 0;
+}
+
+int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid)
+{
+ int err;
+ flask_op_t op;
+
+ op.cmd = FLASK_CONTEXT_TO_SID;
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = do_flask_op(xc_handle, &op)) != 0 )
+ return err;
+
+ sscanf(buf, "%u", sid);
+
+ return 0;
+}
+
+int flask_sid_to_context(int xc_handle, int sid, char *buf, int size)
+{
+ int err;
+ flask_op_t op;
+
+ op.cmd = FLASK_SID_TO_CONTEXT;
+ op.buf = buf;
+ op.size = size;
+
+ snprintf(buf, size, "%u", sid);
+
+ if ( (err = do_flask_op(xc_handle, &op)) != 0 )
+ return err;
+
+ return 0;
+}
+
+int do_flask_op(int xc_handle, flask_op_t *op)
+{
+ int ret = -1;
+ DECLARE_HYPERCALL;
+
+ hypercall.op = __HYPERVISOR_xsm_op;
+ hypercall.arg[0] = (unsigned long)op;
+
+ if ( mlock(op, sizeof(*op)) != 0 )
+ {
+ PERROR("Could not lock memory for Xen hypercall");
+ goto out;
+ }
+
+ if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 )
+ {
+ if ( errno == EACCES )
+ fprintf(stderr, "XSM operation failed!\n");
+ }
+
+ safe_munlock(op, sizeof(*op));
+
+ out:
+ return ret;
+}
+
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/libflask/include/flask_op.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/libflask/include/flask_op.h Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,46 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef __FLASK_OP_H
+#define __FLASK_OP_H
+
+#define FLASK_LOAD 1
+#define FLASK_GETENFORCE 2
+#define FLASK_SETENFORCE 3
+#define FLASK_CONTEXT_TO_SID 4
+#define FLASK_SID_TO_CONTEXT 5
+#define FLASK_ACCESS 6
+#define FLASK_CREATE 7
+#define FLASK_RELABEL 8
+#define FLASK_USER 9
+#define FLASK_POLICYVERS 10
+#define FLASK_GETBOOL 11
+#define FLASK_SETBOOL 12
+#define FLASK_COMMITBOOLS 13
+#define FLASK_MLS 14
+#define FLASK_DISABLE 15
+#define FLASK_GETAVC_THRESHOLD 16
+#define FLASK_SETAVC_THRESHOLD 17
+#define FLASK_AVC_HASHSTATS 18
+#define FLASK_AVC_CACHESTATS 19
+#define FLASK_MEMBER 20
+
+typedef struct flask_op {
+ int cmd;
+ int size;
+ char *buf;
+} flask_op_t;
+
+int flask_load(int xc_handle, char *buf, int size);
+int flask_context_to_sid(int xc_handle, char *buf, int size, u_int32_t *sid);
+int flask_sid_to_context(int xc_handle, int sid, char *buf, int size);
+int do_flask_op(int xc_handle, flask_op_t *op);
+
+#endif
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/loadpolicy/Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/Makefile Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,61 @@
+XEN_ROOT=../../..
+include $(XEN_ROOT)/tools/Rules.mk
+XEN_LIBXC = $(XEN_ROOT)/tools/libxc
+
+INSTALL = install
+INSTALL_DATA = $(INSTALL) -m0644
+INSTALL_PROG = $(INSTALL) -m0755
+INSTALL_DIR = $(INSTALL) -d -m0755
+
+LIBXC_ROOT = $(XEN_ROOT)/tools/libxc
+LIBFLASK_ROOT = $(XEN_ROOT)/tools/flask/libflask
+
+PROFILE=#-pg
+BASECFLAGS=-Wall -g -Werror
+# Make gcc generate dependencies.
+BASECFLAGS += -Wp,-MD,.$(@F).d
+PROG_DEP = .*.d
+BASECFLAGS+= $(PROFILE)
+#BASECFLAGS+= -I$(XEN_ROOT)/tools
+BASECFLAGS+= -I$(LIBXC_ROOT)
+BASECFLAGS+= -I$(LIBFLASK_ROOT)/include
+BASECFLAGS+= -I.
+
+CFLAGS += $(BASECFLAGS)
+LDFLAGS += $(PROFILE) -L$(XEN_LIBXC) -L$(LIBFLASK_ROOT)
+TESTDIR = testsuite/tmp
+TESTFLAGS= -DTESTING
+TESTENV = XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR)
+
+CLIENTS := flask-loadpolicy
+CLIENTS_OBJS := $(patsubst flask-%,%.o,$(CLIENTS))
+
+.PHONY: all
+all: $(CLIENTS)
+
+$(CLIENTS): flask-%: %.o
+ $(LINK.o) $< $(LOADLIBES) $(LDLIBS) -L. -lflask -lxenctrl -o $@
+
+.PHONY: clean
+clean:
+ rm -f *.o *.opic *.so
+ rm -f $(CLIENTS)
+ $(RM) $(PROG_DEP)
+
+.PHONY: print-dir
+print-dir:
+ @echo -n tools/flask/loadpolicy:
+
+.PHONY: print-end
+print-end:
+ @echo
+
+.PHONY: install
+install: all
+ $(INSTALL_DIR) -p $(DESTDIR)/usr/sbin
+ $(INSTALL_PROG) $(CLIENTS) $(DESTDIR)/usr/sbin
+
+-include $(PROG_DEP)
+
+# never delete any intermediate files.
+.SECONDARY:
diff -r 6c8c934b235c -r 993655d24b55 tools/flask/loadpolicy/loadpolicy.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/loadpolicy.c Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,130 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <xenctrl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <flask_op.h>
+
+#define USE_MMAP
+
+static void usage (int argCnt, const char *args[])
+{
+ fprintf(stderr, "Usage: %s <policy.file>\n", args[0]);
+ exit(1);
+}
+
+int main (int argCnt, const char *args[])
+{
+ const char *polFName;
+ int polFd = 0;
+ void *polMem = NULL;
+ void *polMemCp = NULL;
+ struct stat info;
+ int ret;
+ int xch = 0;
+
+ if (argCnt != 2)
+ usage(argCnt, args);
+
+ polFName = args[1];
+ polFd = open(polFName, O_RDONLY);
+ if ( polFd < 0 )
+ {
+ fprintf(stderr, "Error occurred opening policy file '%s': %s\n",
+ polFName, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = stat(polFName, &info);
+ if ( ret < 0 )
+ {
+ fprintf(stderr, "Error occurred retrieving information about"
+ "policy file '%s': %s\n", polFName, strerror(errno));
+ goto cleanup;
+ }
+
+ polMemCp = malloc(info.st_size);
+
+#ifdef USE_MMAP
+ polMem = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, polFd, 0);
+ if ( !polMem )
+ {
+ fprintf(stderr, "Error occurred mapping policy file in memory: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ xch = xc_interface_open();
+ if ( xch < 0 )
+ {
+ fprintf(stderr, "Unable to create interface to xenctrl: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ memcpy(polMemCp, polMem, info.st_size);
+#else
+ ret = read(polFd, polMemCp, info.st_size);
+ if ( ret < 0 )
+ {
+ fprintf(stderr, "Unable to read new Flask policy file: %s\n",
+ strerror(errno));
+ goto cleanup;
+ }
+ else
+ {
+ printf("Read %d bytes from policy file '%s'.\n", ret, polFName);
+ }
+#endif
+
+ ret = flask_load(xch, polMemCp, info.st_size);
+ if ( ret < 0 )
+ {
+ errno = -ret;
+ fprintf(stderr, "Unable to load new Flask policy: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+ else
+ {
+ printf("Successfully loaded policy.\n");
+ }
+
+done:
+ if ( polMemCp )
+ free(polMemCp);
+ if ( polMem )
+ {
+ ret = munmap(polMem, info.st_size);
+ if ( ret < 0 )
+ fprintf(stderr, "Unable to unmap policy memory: %s\n", strerror(errno));
+ }
+ if ( polFd )
+ close(polFd);
+ if ( xch )
+ xc_interface_close(xch);
+
+ return ret;
+
+cleanup:
+ goto done;
+}
diff -r 6c8c934b235c -r 993655d24b55 tools/misc/xenperf.c
--- a/tools/misc/xenperf.c Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/misc/xenperf.c Fri Aug 31 11:37:20 2007 +0100
@@ -46,7 +46,7 @@ const char *hypercall_name_table[64] =
X(vcpu_op),
X(set_segment_base),
X(mmuext_op),
- X(acm_op),
+ X(xsm_op),
X(nmi_op),
X(sched_op),
X(callback_op),
diff -r 6c8c934b235c -r 993655d24b55 tools/python/Makefile
--- a/tools/python/Makefile Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/Makefile Fri Aug 31 11:37:20 2007 +0100
@@ -1,5 +1,13 @@ XEN_ROOT = ../..
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Rules.mk
+
+XEN_SECURITY_MODULE = dummy
+ifeq ($(FLASK_ENABLE),y)
+XEN_SECURITY_MODULE = flask
+endif
+ifeq ($(ACM_SECURITY),y)
+XEN_SECURITY_MODULE = acm
+endif

.PHONY: all
all: build
@@ -16,9 +24,9 @@ NLSDIR = /usr/share/locale

.PHONY: build buildpy
buildpy:
- CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
+ CC="$(CC)" CFLAGS="$(CFLAGS)" XEN_SECURITY_MODULE="$(XEN_SECURITY_MODULE)" python setup.py build

-build: buildpy refresh-pot refresh-po $(CATALOGS)
+build: xsm.py buildpy refresh-pot refresh-po $(CATALOGS)

# NB we take care to only update the .pot file it strings have
# actually changed. This is complicated by the embedded date
@@ -53,6 +61,18 @@ refresh-po: $(POTFILE)
%.mo: %.po
$(MSGFMT) -c -o $@ $<

+xsm.py:
+ @(set -e; \
+ echo "XEN_SECURITY_MODULE = \""$(XEN_SECURITY_MODULE)"\""; \
+ echo "from xsm_core import *"; \
+ echo ""; \
+ echo "import xen.util.xsm."$(XEN_SECURITY_MODULE)"."$(XEN_SECURITY_MODULE)" as xsm_module"; \
+ echo ""; \
+ echo "xsm_init(xsm_module)"; \
+ echo "from xen.util.xsm."$(XEN_SECURITY_MODULE)"."$(XEN_SECURITY_MODULE)" import *"; \
+ echo "del xsm_module"; \
+ echo "") >xen/util/xsm/$@
+
.PHONY: install
ifndef XEN_PYTHON_NATIVE_INSTALL
install: LIBPATH=$(shell PYTHONPATH=xen/util python -c "import auxbin; print auxbin.libpath()")
@@ -84,4 +104,4 @@ test:

.PHONY: clean
clean:
- rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS)
+ rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS) xen/util/xsm/xsm.py
diff -r 6c8c934b235c -r 993655d24b55 tools/python/setup.py
--- a/tools/python/setup.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/setup.py Fri Aug 31 11:37:20 2007 +0100
@@ -44,6 +44,14 @@ acm = Extension("acm",
libraries = libraries,
sources = [ "xen/lowlevel/acm/acm.c" ])

+flask = Extension("flask",
+ extra_compile_args = extra_compile_args,
+ include_dirs = include_dirs + [ "xen/lowlevel/flask" ] +
+ [ "../flask/libflask/include" ],
+ library_dirs = library_dirs + [ "../flask/libflask" ],
+ libraries = libraries + [ "flask" ],
+ sources = [ "xen/lowlevel/flask/flask.c" ])
+
ptsname = Extension("ptsname",
extra_compile_args = extra_compile_args,
include_dirs = include_dirs + [ "ptsname" ],
@@ -51,9 +59,14 @@ ptsname = Extension("ptsname",
libraries = libraries,
sources = [ "ptsname/ptsname.c" ])

-modules = [ xc, xs, acm, ptsname ]
+modules = [ xc, xs, ptsname ]
if os.uname()[0] == 'SunOS':
modules.append(scf)
+
+if os.environ.get('XEN_SECURITY_MODULE') == 'acm':
+ modules.append(acm)
+if os.environ.get('XEN_SECURITY_MODULE') == 'flask':
+ modules.append(flask)

setup(name = 'xen',
version = '3.0',
@@ -61,6 +74,10 @@ setup(name = 'xen',
packages = [.'xen',
'xen.lowlevel',
'xen.util',
+ 'xen.util.xsm',
+ 'xen.util.xsm.dummy',
+ 'xen.util.xsm.flask',
+ 'xen.util.xsm.acm',
'xen.xend',
'xen.xend.server',
'xen.xend.xenstore',
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/lowlevel/flask/flask.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/lowlevel/flask/flask.c Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * flask.c
+ *
+ * Authors: George Coker, <gscoker@alpha.ncsc.mil>
+ * Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <Python.h>
+#include <xenctrl.h>
+
+#include <flask_op.h>
+
+#define PKG "xen.lowlevel.flask"
+#define CLS "flask"
+
+#define CTX_LEN 1024
+
+static PyObject *xc_error_obj;
+
+typedef struct {
+ PyObject_HEAD;
+ int xc_handle;
+} XcObject;
+
+static PyObject *pyflask_context_to_sid(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ int xc_handle;
+ char *ctx;
+ char *buf;
+ uint32_t len;
+ uint32_t sid;
+ int ret;
+
+ static char *kwd_list[] = { "context", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list,
+ &ctx) )
+ return NULL;
+
+ len = strlen(ctx);
+
+ buf = malloc(len);
+ if (!buf) {
+ errno = -ENOMEM;
+ PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ memcpy(buf, ctx, len);
+
+ xc_handle = xc_interface_open();
+ if (xc_handle < 0) {
+ errno = xc_handle;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ ret = flask_context_to_sid(xc_handle, buf, len, &sid);
+
+ xc_interface_close(xc_handle);
+
+ free(buf);
+
+ if ( ret != 0 ) {
+ errno = -ret;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ return PyInt_FromLong(sid);
+}
+
+static PyObject *pyflask_sid_to_context(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ int xc_handle;
+ uint32_t sid;
+ char ctx[CTX_LEN];
+ uint32_t ctx_len = CTX_LEN;
+ int ret;
+
+ static char *kwd_list[] = { "sid", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
+ &sid) )
+ return NULL;
+
+ xc_handle = xc_interface_open();
+ if (xc_handle < 0) {
+ errno = xc_handle;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ ret = flask_sid_to_context(xc_handle, sid, ctx, ctx_len);
+
+ xc_interface_close(xc_handle);
+
+ if ( ret != 0 ) {
+ errno = -ret;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ return Py_BuildValue("s", ctx, ctx_len);
+}
+
+
+static PyMethodDef pyflask_methods[] = {
+ { "flask_context_to_sid",
+ (PyCFunction)pyflask_context_to_sid,
+ METH_KEYWORDS, "\n"
+ "Convert a context string to a dynamic SID.\n"
+ " context [str]: String specifying context to be converted\n"
+ "Returns: [int]: Numeric SID on success; -1 on error.\n" },
+
+ { "flask_sid_to_context",
+ (PyCFunction)pyflask_sid_to_context,
+ METH_KEYWORDS, "\n"
+ "Convert a dynamic SID to context string.\n"
+ " context [int]: SID to be converted\n"
+ "Returns: [str]: Numeric SID on success; -1 on error.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initflask(void)
+{
+ Py_InitModule("flask", pyflask_methods);
+}
+
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/acmpolicy.py
--- a/tools/python/xen/util/acmpolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/util/acmpolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -1,4 +1,4 @@
-#============================================================================
+ #============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
@@ -23,10 +23,11 @@ import array
import array
from xml.dom import minidom, Node
from xen.xend.XendLogging import log
-from xen.util import security, xsconstants, bootloader, mkdir
+from xen.util import xsconstants, bootloader, mkdir
from xen.util.xspolicy import XSPolicy
-from xen.util.security import ACMError
from xen.xend.XendError import SecurityError
+import xen.util.xsm.acm.acm as security
+from xen.util.xsm.xsm import XSMError

ACM_POLICIES_DIR = security.policy_dir_prefix + "/"

@@ -1240,8 +1241,8 @@ class ACMPolicy(XSPolicy):

(major, minor) = self.getVersionTuple()
hdr_bin = struct.pack(headerformat,
+ ACM_MAGIC,
ACM_POLICY_VERSION,
- ACM_MAGIC,
totallen_bin,
polref_offset,
primpolcode,
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/__init__.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,2 @@
+
+
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/acm/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/__init__.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,1 @@
+
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/acm/acm.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/acm.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,1283 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 International Business Machines Corp.
+# Author: Reiner Sailer
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+# Author: Stefan Berger <stefanb@us.ibm.com>
+#============================================================================
+
+import commands
+import logging
+import os, string, re
+import threading
+import struct
+import stat
+from xen.lowlevel import acm
+from xen.xend import sxp
+from xen.xend import XendConstants
+from xen.xend.XendLogging import log
+from xen.xend.XendError import VmError
+from xen.util import dictio, xsconstants
+from xen.xend.XendConstants import *
+
+#global directories and tools for security management
+policy_dir_prefix = "/etc/xen/acm-security/policies"
+res_label_filename = policy_dir_prefix + "/resource_labels"
+boot_filename = "/boot/grub/menu.lst"
+altboot_filename = "/boot/grub/grub.conf"
+xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
+xensec_tool = "/usr/sbin/xensec_tool"
+
+#global patterns for map file
+#police_reference_tagname = "POLICYREFERENCENAME"
+primary_entry_re = re.compile("\s*PRIMARY\s+.*", re.IGNORECASE)
+secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE)
+label_template_re = re.compile(".*security_label_template.xml", re.IGNORECASE)
+mapping_filename_re = re.compile(".*\.map", re.IGNORECASE)
+policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE)
+vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE)
+res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE)
+all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE)
+access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE)
+
+#global patterns for boot configuration file
+xen_title_re = re.compile("\s*title\s+XEN", re.IGNORECASE)
+any_title_re = re.compile("\s*title\s", re.IGNORECASE)
+xen_kernel_re = re.compile("\s*kernel.*xen.*\.gz", re.IGNORECASE)
+kernel_ver_re = re.compile("\s*module.*vmlinuz", re.IGNORECASE)
+any_module_re = re.compile("\s*module\s", re.IGNORECASE)
+empty_line_re = re.compile("^\s*$")
+binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
+policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
+
+#decision hooks known to the hypervisor
+ACMHOOK_sharing = 1
+ACMHOOK_authorization = 2
+
+#other global variables
+NULL_SSIDREF = 0
+
+#general Rlock for map files; only one lock for all mapfiles
+__mapfile_lock = threading.RLock()
+__resfile_lock = threading.RLock()
+
+log = logging.getLogger("xend.util.security")
+
+# Our own exception definition. It is masked (pass) if raised and
+# whoever raises this exception must provide error information.
+class ACMError(Exception):
+ def __init__(self,value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+
+
+def err(msg):
+ """Raise ACM exception.
+ """
+ raise ACMError(msg)
+
+
+
+active_policy = None
+
+
+def mapfile_lock():
+ __mapfile_lock.acquire()
+
+def mapfile_unlock():
+ __mapfile_lock.release()
+
+
+def refresh_security_policy():
+ """
+ retrieves security policy
+ """
+ global active_policy
+
+ try:
+ active_policy = acm.policy()
+ except:
+ active_policy = "INACTIVE"
+
+# now set active_policy
+refresh_security_policy()
+
+def on():
+ """
+ returns none if security policy is off (not compiled),
+ any string otherwise, use it: if not security.on() ...
+ """
+ refresh_security_policy()
+ return (active_policy not in ['INACTIVE', 'NULL'])
+
+
+def calc_dom_ssidref_from_info(info):
+ """
+ Calculate a domain's ssidref from the security_label in its
+ info.
+ This function is called before the domain is started and
+ makes sure that:
+ - the type of the policy is the same as indicated in the label
+ - the name of the policy is the same as indicated in the label
+ - calculates an up-to-date ssidref for the domain
+ The latter is necessary since the domain's ssidref could have
+ changed due to changes to the policy.
+ """
+ import xen.xend.XendConfig
+ if isinstance(info, xen.xend.XendConfig.XendConfig):
+ if info.has_key('security_label'):
+ seclab = info['security_label']
+ tmp = seclab.split(":")
+ if len(tmp) != 3:
+ raise VmError("VM label '%s' in wrong format." % seclab)
+ typ, policyname, vmlabel = seclab.split(":")
+ if typ != xsconstants.ACM_POLICY_ID:
+ raise VmError("Policy type '%s' must be changed." % typ)
+ refresh_security_policy()
+ if active_policy != policyname:
+ raise VmError("Active policy '%s' different than "
+ "what in VM's label ('%s')." %
+ (active_policy, policyname))
+ ssidref = label2ssidref(vmlabel, policyname, "dom")
+ return ssidref
+ else:
+ return 0x0
+ raise VmError("security.calc_dom_ssidref_from_info: info of type '%s'"
+ "not supported." % type(info))
+
+
+def getmapfile(policyname):
+ """
+ in: if policyname is None then the currently
+ active hypervisor policy is used
+ out: 1. primary policy, 2. secondary policy,
+ 3. open file descriptor for mapping file, and
+ 4. True if policy file is available, False otherwise
+ """
+ if not policyname:
+ policyname = active_policy
+ map_file_ok = False
+ primary = None
+ secondary = None
+ #strip last part of policy as file name part
+ policy_dir_list = string.split(policyname, ".")
+ policy_file = policy_dir_list.pop()
+ if len(policy_dir_list) > 0:
+ policy_dir = string.join(policy_dir_list, "/") + "/"
+ else:
+ policy_dir = ""
+
+ map_filename = policy_dir_prefix + "/" + policy_dir + policy_file + ".map"
+ # check if it is there, if not check if policy file is there
+ if not os.path.isfile(map_filename):
+ policy_filename = policy_dir_prefix + "/" + policy_dir + policy_file + "-security_policy.xml"
+ if not os.path.isfile(policy_filename):
+ err("Policy file \'" + policy_filename + "\' not found.")
+ else:
+ err("Mapping file \'" + map_filename + "\' not found." +
+ " Use xm makepolicy to create it.")
+
+ f = open(map_filename)
+ for line in f:
+ if policy_reference_entry_re.match(line):
+ l = line.split()
+ if (len(l) == 2) and (l[1] == policyname):
+ map_file_ok = True
+ elif primary_entry_re.match(line):
+ l = line.split()
+ if len(l) == 2:
+ primary = l[1]
+ elif secondary_entry_re.match(line):
+ l = line.split()
+ if len(l) == 2:
+ secondary = l[1]
+ f.close()
+ f = open(map_filename)
+ if map_file_ok and primary and secondary:
+ return (primary, secondary, f, True)
+ else:
+ err("Mapping file inconsistencies found. Try makepolicy to create a new one.")
+
+
+
+def ssidref2label(ssidref_var):
+ """
+ returns labelname corresponding to ssidref;
+ maps current policy to default directory
+ to find mapping file
+ """
+ #1. translated permitted input formats
+ if isinstance(ssidref_var, str):
+ ssidref_var.strip()
+ if ssidref_var[0:2] == "0x":
+ ssidref = int(ssidref_var[2:], 16)
+ else:
+ ssidref = int(ssidref_var)
+ elif isinstance(ssidref_var, int):
+ ssidref = ssidref_var
+ else:
+ err("Instance type of ssidref not supported (must be of type 'str' or 'int')")
+
+ if ssidref == 0:
+ from xen.util.acmpolicy import ACM_LABEL_UNLABELED
+ return ACM_LABEL_UNLABELED
+
+ try:
+ mapfile_lock()
+
+ (primary, secondary, f, pol_exists) = getmapfile(None)
+ if not f:
+ if (pol_exists):
+ err("Mapping file for policy not found.\n" +
+ "Please use makepolicy command to create mapping file!")
+ else:
+ err("Policy file for \'" + active_policy + "\' not found.")
+
+ #2. get labelnames for both ssidref parts
+ pri_ssid = ssidref & 0xffff
+ sec_ssid = ssidref >> 16
+ pri_null_ssid = NULL_SSIDREF & 0xffff
+ sec_null_ssid = NULL_SSIDREF >> 16
+ pri_labels = []
+ sec_labels = []
+ labels = []
+
+ for line in f:
+ l = line.split()
+ if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+ continue
+ if primary and (l[2] == primary) and (int(l[4], 16) == pri_ssid):
+ pri_labels.append(l[3])
+ if secondary and (l[2] == secondary) and (int(l[4], 16) == sec_ssid):
+ sec_labels.append(l[3])
+ f.close()
+ finally:
+ mapfile_unlock()
+
+ #3. get the label that is in both lists (combination must be a single label)
+ if (primary == "CHWALL") and (pri_ssid == pri_null_ssid) and (sec_ssid != sec_null_ssid):
+ labels = sec_labels
+ elif (secondary == "CHWALL") and (pri_ssid != pri_null_ssid) and (sec_ssid == sec_null_ssid):
+ labels = pri_labels
+ elif secondary == "NULL":
+ labels = pri_labels
+ else:
+ for i in pri_labels:
+ for j in sec_labels:
+ if (i==j):
+ labels.append(i)
+ if len(labels) != 1:
+ err("Label for ssidref \'" + str(ssidref) +
+ "\' unknown or not unique in policy \'" + active_policy + "\'")
+
+ return labels[0]
+
+
+
+def label2ssidref(labelname, policyname, typ):
+ """
+ returns ssidref corresponding to labelname;
+ maps current policy to default directory
+ to find mapping file """
+
+ if policyname in ['NULL', 'INACTIVE', 'DEFAULT']:
+ err("Cannot translate labels for \'" + policyname + "\' policy.")
+
+ allowed_types = ['ANY']
+ if typ == 'dom':
+ allowed_types.append('VM')
+ elif typ == 'res':
+ allowed_types.append('RES')
+ else:
+ err("Invalid type. Must specify 'dom' or 'res'.")
+
+ try:
+ mapfile_lock()
+ (primary, secondary, f, pol_exists) = getmapfile(policyname)
+
+ #2. get labelnames for ssidref parts and find a common label
+ pri_ssid = []
+ sec_ssid = []
+ for line in f:
+ l = line.split()
+ if (len(l) < 5) or (l[0] != "LABEL->SSID"):
+ continue
+ if primary and (l[1] in allowed_types) and \
+ (l[2] == primary) and \
+ (l[3] == labelname):
+ pri_ssid.append(int(l[4], 16))
+ if secondary and (l[1] in allowed_types) and \
+ (l[2] == secondary) and \
+ (l[3] == labelname):
+ sec_ssid.append(int(l[4], 16))
+ f.close()
+ if (typ == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
+ pri_ssid.append(NULL_SSIDREF)
+ elif (typ == 'res') and (secondary == "CHWALL") and \
+ (len(sec_ssid) == 0):
+ sec_ssid.append(NULL_SSIDREF)
+
+ #3. sanity check and composition of ssidref
+ if (len(pri_ssid) == 0) or ((len(sec_ssid) == 0) and \
+ (secondary != "NULL")):
+ err("Label \'" + labelname + "\' not found.")
+ elif (len(pri_ssid) > 1) or (len(sec_ssid) > 1):
+ err("Label \'" + labelname + "\' not unique in policy (policy error)")
+ if secondary == "NULL":
+ return pri_ssid[0]
+ else:
+ return (sec_ssid[0] << 16) | pri_ssid[0]
+ finally:
+ mapfile_unlock()
+
+
+def refresh_ssidref(config):
+ """
+ looks up ssidref from security field
+ and refreshes the value if label exists
+ """
+ #called by dom0, policy could have changed after xen.utils.security was initialized
+ refresh_security_policy()
+
+ security = None
+ if isinstance(config, dict):
+ security = config['security']
+ elif isinstance(config, list):
+ security = sxp.child_value(config, 'security')
+ else:
+ err("Instance type of config parameter not supported.")
+ if not security:
+ #nothing to do (no security label attached)
+ return config
+
+ policyname = None
+ labelname = None
+ # compose new security field
+ for idx in range(0, len(security)):
+ if security[idx][0] == 'ssidref':
+ security.pop(idx)
+ break
+ elif security[idx][0] == 'access_control':
+ for jdx in [1, 2]:
+ if security[idx][jdx][0] == 'label':
+ labelname = security[idx][jdx][1]
+ elif security[idx][jdx][0] == 'policy':
+ policyname = security[idx][jdx][1]
+ else:
+ err("Illegal field in access_control")
+ #verify policy is correct
+ if active_policy != policyname:
+ err("Policy \'" + str(policyname) +
+ "\' in label does not match active policy \'"
+ + str(active_policy) +"\'!")
+
+ new_ssidref = label2ssidref(labelname, policyname, 'dom')
+ if not new_ssidref:
+ err("SSIDREF refresh failed!")
+
+ security.append([ 'ssidref',str(new_ssidref)])
+ security = ['security', security ]
+
+ for idx in range(0,len(config)):
+ if config[idx][0] == 'security':
+ config.pop(idx)
+ break
+ config.append(security)
+
+
+
+def get_ssid(domain):
+ """
+ enables domains to retrieve the label / ssidref of a running domain
+ """
+ if not on():
+ err("No policy active.")
+
+ if isinstance(domain, str):
+ domain_int = int(domain)
+ elif isinstance(domain, int):
+ domain_int = domain
+ else:
+ err("Illegal parameter type.")
+ try:
+ ssid_info = acm.getssid(int(domain_int))
+ except:
+ err("Cannot determine security information.")
+
+ if active_policy in ["DEFAULT"]:
+ label = "DEFAULT"
+ else:
+ label = ssidref2label(ssid_info["ssidref"])
+ return(ssid_info["policyreference"],
+ label,
+ ssid_info["policytype"],
+ ssid_info["ssidref"])
+
+
+
+def get_decision(arg1, arg2):
+ """
+ enables domains to retrieve access control decisions from
+ the hypervisor Access Control Module.
+ IN: args format = ['domid', id] or ['ssidref', ssidref]
+ or ['access_control', ['policy', policy], ['label', label], ['type', type]]
+ """
+
+ if not on():
+ err("No policy active.")
+
+ #translate labels before calling low-level function
+ if arg1[0] == 'access_control':
+ if (arg1[1][0] != 'policy') or (arg1[2][0] != 'label') or (arg1[3][0] != 'type'):
+ err("Argument type not supported.")
+ ssidref = label2ssidref(arg1[2][1], arg1[1][1], arg1[3][1])
+ arg1 = ['ssidref', str(ssidref)]
+ if arg2[0] == 'access_control':
+ if (arg2[1][0] != 'policy') or (arg2[2][0] != 'label') or (arg2[3][0] != 'type'):
+ err("Argument type not supported.")
+ ssidref = label2ssidref(arg2[2][1], arg2[1][1], arg2[3][1])
+ arg2 = ['ssidref', str(ssidref)]
+
+ # accept only int or string types for domid and ssidref
+ if isinstance(arg1[1], int):
+ arg1[1] = str(arg1[1])
+ if isinstance(arg2[1], int):
+ arg2[1] = str(arg2[1])
+ if not isinstance(arg1[1], str) or not isinstance(arg2[1], str):
+ err("Invalid id or ssidref type, string or int required")
+
+ try:
+ decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1],
+ ACMHOOK_sharing)
+ except:
+ err("Cannot determine decision.")
+
+ if decision:
+ return decision
+ else:
+ err("Cannot determine decision (Invalid parameter).")
+
+
+def has_authorization(ssidref):
+ """ Check if the domain with the given ssidref has authorization to
+ run on this system. To have authoriztion dom0's STE types must
+ be a superset of that of the domain's given through its ssidref.
+ """
+ rc = True
+ dom0_ssidref = int(acm.getssid(0)['ssidref'])
+ decision = acm.getdecision('ssidref', str(dom0_ssidref),
+ 'ssidref', str(ssidref),
+ ACMHOOK_authorization)
+ if decision == "DENIED":
+ rc = False
+ return rc
+
+
+def hv_chg_policy(bin_pol, del_array, chg_array):
+ """
+ Change the binary policy in the hypervisor
+ The 'del_array' and 'chg_array' give hints about deleted ssidrefs
+ and changed ssidrefs which can be due to deleted VM labels
+ or reordered VM labels
+ """
+ rc = -xsconstants.XSERR_GENERAL_FAILURE
+ errors = ""
+ if not on():
+ err("No policy active.")
+ try:
+ rc, errors = acm.chgpolicy(bin_pol, del_array, chg_array)
+ except Exception, e:
+ pass
+ if len(errors) > 0:
+ rc = -xsconstants.XSERR_HV_OP_FAILED
+ return rc, errors
+
+
+def make_policy(policy_name):
+ policy_file = string.join(string.split(policy_name, "."), "/")
+ if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"):
+ err("Unknown policy \'" + policy_name + "\'")
+
+ (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file)
+ if ret:
+ err("Creating policy failed:\n" + output)
+
+def load_policy(policy_name):
+ global active_policy
+ policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/")
+ if not os.path.isfile(policy_file + ".bin"):
+ if os.path.isfile(policy_file + "-security_policy.xml"):
+ err("Binary file does not exist." +
+ "Please use makepolicy to build the policy binary.")
+ else:
+ err("Unknown Policy " + policy_name)
+
+ #require this policy to be the first or the same as installed
+ if active_policy not in ['DEFAULT', policy_name]:
+ err("Active policy \'" + active_policy +
+ "\' incompatible with new policy \'" + policy_name + "\'")
+ (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin")
+ if ret:
+ err("Loading policy failed:\n" + output)
+ else:
+ # refresh active policy
+ refresh_security_policy()
+
+
+
+def dump_policy():
+ if active_policy in ['NULL', 'INACTIVE']:
+ err("\'" + active_policy + "\' policy. Nothing to dump.")
+
+ (ret, output) = commands.getstatusoutput(xensec_tool + " getpolicy")
+ if ret:
+ err("Dumping hypervisor policy failed:\n" + output)
+ print output
+
+
+
+def list_labels(policy_name, condition):
+ if (not policy_name) and (active_policy) in ["NULL", "INACTIVE", "DEFAULT"]:
+ err("Current policy \'" + active_policy + "\' has no labels defined.\n")
+
+ (primary, secondary, f, pol_exists) = getmapfile(policy_name)
+ if not f:
+ if pol_exists:
+ err("Cannot find mapfile for policy \'" + policy_name +
+ "\'.\nPlease use makepolicy to create mapping file.")
+ else:
+ err("Unknown policy \'" + policy_name + "\'")
+
+ labels = []
+ for line in f:
+ if condition.match(line):
+ label = line.split()[3]
+ if label not in labels:
+ labels.append(label)
+ return labels
+
+
+def get_res_label(resource):
+ """Returns resource label information (policytype, label, policy) if
+ it exists. Otherwise returns null label and policy.
+ """
+ def default_res_label():
+ ssidref = NULL_SSIDREF
+ if on():
+ label = ssidref2label(ssidref)
+ else:
+ label = None
+ return (xsconstants.ACM_POLICY_ID, 'NULL', label)
+
+
+ tmp = get_resource_label(resource)
+ if len(tmp) == 2:
+ policytype = xsconstants.ACM_POLICY_ID
+ policy, label = tmp
+ elif len(tmp) == 3:
+ policytype, policy, label = tmp
+ else:
+ policytype, policy, label = default_res_label()
+
+ return (policytype, label, policy)
+
+
+def get_res_security_details(resource):
+ """Returns the (label, ssidref, policy) associated with a given
+ resource from the global resource label file.
+ """
+ def default_security_details():
+ ssidref = NULL_SSIDREF
+ if on():
+ label = ssidref2label(ssidref)
+ else:
+ label = None
+ policy = active_policy
+ return (label, ssidref, policy)
+
+ (label, ssidref, policy) = default_security_details()
+
+ # find the entry associated with this resource
+ (policytype, label, policy) = get_res_label(resource)
+ if policy == 'NULL':
+ log.info("Resource label for "+resource+" not in file, using DEFAULT.")
+ return default_security_details()
+
+ # is this resource label for the running policy?
+ if policy == active_policy:
+ ssidref = label2ssidref(label, policy, 'res')
+ else:
+ log.info("Resource label not for active policy, using DEFAULT.")
+ return default_security_details()
+
+ return (label, ssidref, policy)
+
+def security_label_to_details(seclab):
+ """ Convert a Xen-API type of security label into details """
+ def default_security_details():
+ ssidref = NULL_SSIDREF
+ if on():
+ label = ssidref2label(ssidref)
+ else:
+ label = None
+ policy = active_policy
+ return (label, ssidref, policy)
+
+ (policytype, policy, label) = seclab.split(":")
+
+ # is this resource label for the running policy?
+ if policy == active_policy:
+ ssidref = label2ssidref(label, policy, 'res')
+ else:
+ log.info("Resource label not for active policy, using DEFAULT.")
+ return default_security_details()
+
+ return (label, ssidref, policy)
+
+def unify_resname(resource, mustexist=True):
+ """Makes all resource locations absolute. In case of physical
+ resources, '/dev/' is added to local file names"""
+
+ if not resource:
+ return resource
+
+ # sanity check on resource name
+ try:
+ (typ, resfile) = resource.split(":", 1)
+ except:
+ err("Resource spec '%s' contains no ':' delimiter" % resource)
+
+ if typ == "tap":
+ try:
+ (subtype, resfile) = resfile.split(":")
+ except:
+ err("Resource spec '%s' contains no tap subtype" % resource)
+
+ import os
+ if typ in ["phy", "tap"]:
+ if not resfile.startswith("/"):
+ resfile = "/dev/" + resfile
+ if mustexist:
+ stats = os.lstat(resfile)
+ if stat.S_ISLNK(stats[stat.ST_MODE]):
+ resolved = os.readlink(resfile)
+ if resolved[0] != "/":
+ resfile = os.path.join(os.path.dirname(resfile), resolved)
+ resfile = os.path.abspath(resfile)
+ else:
+ resfile = resolved
+ stats = os.lstat(resfile)
+ if not (stat.S_ISBLK(stats[stat.ST_MODE])):
+ err("Invalid resource")
+
+ if typ in [ "file", "tap" ]:
+ if mustexist:
+ stats = os.lstat(resfile)
+ if stat.S_ISLNK(stats[stat.ST_MODE]):
+ resfile = os.readlink(resfile)
+ stats = os.lstat(resfile)
+ if not stat.S_ISREG(stats[stat.ST_MODE]):
+ err("Invalid resource")
+
+ #file: resources must specified with absolute path
+ #vlan resources don't start with '/'
+ if typ != "vlan":
+ if (not resfile.startswith("/")) or \
+ (mustexist and not os.path.exists(resfile)):
+ err("Invalid resource.")
+
+ # from here on absolute file names with resources
+ if typ == "tap":
+ typ = typ + ":" + subtype
+ resource = typ + ":" + resfile
+ return resource
+
+
+def res_security_check(resource, domain_label):
+ """Checks if the given resource can be used by the given domain
+ label. Returns 1 if the resource can be used, otherwise 0.
+ """
+ rtnval = 1
+
+ # if security is on, ask the hypervisor for a decision
+ if on():
+ #build canonical resource name
+ resource = unify_resname(resource)
+
+ (label, ssidref, policy) = get_res_security_details(resource)
+ domac = ['access_control']
+ domac.append(['policy', active_policy])
+ domac.append(['label', domain_label])
+ domac.append(['type', 'dom'])
+ decision = get_decision(domac, ['ssidref', str(ssidref)])
+
+ # provide descriptive error messages
+ if decision == 'DENIED':
+ if label == ssidref2label(NULL_SSIDREF):
+ raise ACMError("Resource '"+resource+"' is not labeled")
+ rtnval = 0
+ else:
+ raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
+ rtnval = 0
+
+ # security is off, make sure resource isn't labeled
+ else:
+ # Note, we can't canonicalise the resource here, because people using
+ # xm without ACM are free to use relative paths.
+ (policytype, label, policy) = get_res_label(resource)
+ if policy != 'NULL':
+ raise ACMError("Security is off, but '"+resource+"' is labeled")
+ rtnval = 0
+
+ return rtnval
+
+def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label):
+ """Checks if the given resource can be used by the given domain
+ label. Returns 1 if the resource can be used, otherwise 0.
+ """
+ rtnval = 1
+ # if security is on, ask the hypervisor for a decision
+ if on():
+ typ, dpolicy, domain_label = xapi_dom_label.split(":")
+ if not dpolicy or not domain_label:
+ raise VmError("VM security label in wrong format.")
+ if active_policy != rpolicy:
+ raise VmError("Resource's policy '%s' != active policy '%s'" %
+ (rpolicy, active_policy))
+ domac = ['access_control']
+ domac.append(['policy', active_policy])
+ domac.append(['label', domain_label])
+ domac.append(['type', 'dom'])
+ decision = get_decision(domac, ['ssidref', str(rssidref)])
+
+ log.info("Access Control Decision : %s" % decision)
+ # provide descriptive error messages
+ if decision == 'DENIED':
+ if rlabel == ssidref2label(NULL_SSIDREF):
+ #raise ACMError("Resource is not labeled")
+ rtnval = 0
+ else:
+ #raise ACMError("Permission denied for resource because label '"+rlabel+"' is not allowed")
+ rtnval = 0
+
+ # security is off, make sure resource isn't labeled
+ else:
+ # Note, we can't canonicalise the resource here, because people using
+ # xm without ACM are free to use relative paths.
+ if rpolicy != 'NULL':
+ #raise ACMError("Security is off, but resource is labeled")
+ rtnval = 0
+
+ return rtnval
+
+
+def validate_label(label, policyref):
+ """
+ Make sure that this label is part of the currently enforced policy
+ and that it reference the current policy.
+ """
+ rc = xsconstants.XSERR_SUCCESS
+ from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+ curpol = XSPolicyAdminInstance().get_loaded_policy()
+ if not curpol or curpol.get_name() != policyref:
+ rc = -xsconstants.XSERR_BAD_LABEL
+ else:
+ try:
+ label2ssidref(label, curpol.get_name() , 'res')
+ except:
+ rc = -xsconstants.XSERR_BAD_LABEL
+ return rc
+
+
+def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi):
+ """Assign a resource label to a resource
+ @param resource: The name of a resource, i.e., "phy:/dev/hda", or
+ "tap:qcow:/path/to/file.qcow"
+
+ @param reslabel_xapi: A resource label foramtted as in all other parts of
+ the Xen-API, i.e., ACM:xm-test:blue"
+ @rtype: int
+ @return Success (0) or failure value (< 0)
+ """
+ olabel = ""
+ if reslabel_xapi == "":
+ return rm_resource_label(resource, oldlabel_xapi)
+ typ, policyref, label = reslabel_xapi.split(":")
+ if typ != xsconstants.ACM_POLICY_ID:
+ return -xsconstants.XSERR_WRONG_POLICY_TYPE
+ if not policyref or not label:
+ return -xsconstants.XSERR_BAD_LABEL_FORMAT
+ if oldlabel_xapi not in [ "" ]:
+ tmp = oldlabel_xapi.split(":")
+ if len(tmp) != 3:
+ return -xsconstants.XSERR_BAD_LABEL_FORMAT
+ otyp, opolicyref, olabel = tmp
+ # Only ACM is supported
+ if otyp != xsconstants.ACM_POLICY_ID and \
+ otyp != xsconstants.INVALID_POLICY_PREFIX + \
+ xsconstants.ACM_POLICY_ID:
+ return -xsconstants.XSERR_WRONG_POLICY_TYPE
+ rc = validate_label(label, policyref)
+ if rc != xsconstants.XSERR_SUCCESS:
+ return rc
+ return set_resource_label(resource, typ, policyref, label, olabel)
+
+
+def is_resource_in_use(resource):
+ """ Investigate all running domains whether they use this device """
+ from xen.xend import XendDomain
+ dominfos = XendDomain.instance().list('all')
+ lst = []
+ for dominfo in dominfos:
+ if is_resource_in_use_by_dom(dominfo, resource):
+ lst.append(dominfo)
+ return lst
+
+def devices_equal(res1, res2, mustexist=True):
+ """ Determine whether two devices are equal """
+ return (unify_resname(res1, mustexist) ==
+ unify_resname(res2, mustexist))
+
+def is_resource_in_use_by_dom(dominfo, resource):
+ """ Determine whether a resources is in use by a given domain
+ @return True or False
+ """
+ if not dominfo.domid:
+ return False
+ if dominfo._stateGet() not in [ DOM_STATE_RUNNING ]:
+ return False
+ devs = dominfo.info['devices']
+ uuids = devs.keys()
+ for uuid in uuids:
+ dev = devs[uuid]
+ if len(dev) >= 2 and dev[1].has_key('uname'):
+ # dev[0] is type, i.e. 'vbd'
+ if devices_equal(dev[1]['uname'], resource, mustexist=False):
+ log.info("RESOURCE IN USE: Domain %d uses %s." %
+ (dominfo.domid, resource))
+ return True
+ return False
+
+
+def get_domain_resources(dominfo):
+ """ Collect all resources of a domain in a map where each entry of
+ the map is a list.
+ Entries are strored in the following formats:
+ tap:qcow:/path/xyz.qcow
+ """
+ resources = { 'vbd' : [], 'tap' : [], 'vif' : []}
+ devs = dominfo.info['devices']
+ uuids = devs.keys()
+ for uuid in uuids:
+ dev = devs[uuid]
+ typ = dev[0]
+ if typ in [ 'vbd', 'tap' ]:
+ resources[typ].append(dev[1]['uname'])
+ if typ in [ 'vif' ]:
+ sec_lab = dev[1].get('security_label')
+ if sec_lab:
+ resources[typ].append(sec_lab)
+ else:
+ resources[typ].append("%s:%s:%s" %
+ (xsconstants.ACM_POLICY_ID,
+ active_policy,
+ ACM_LABEL_UNLABELED))
+
+ return resources
+
+
+def resources_compatible_with_vmlabel(xspol, dominfo, vmlabel):
+ """
+ Check whether the resources' labels are compatible with the
+ given VM label. This is a function to be used when for example
+ a running domain is to get the new label 'vmlabel'
+ """
+ if not xspol:
+ return False
+
+ try:
+ __resfile_lock.acquire()
+ try:
+ access_control = dictio.dict_read("resources",
+ res_label_filename)
+ except:
+ return False
+ return __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
+ access_control)
+ finally:
+ __resfile_lock.release()
+ return False
+
+
+def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel,
+ access_control):
+ """
+ Check whether the resources' labels are compatible with the
+ given VM label. The access_control parameter provides a
+ dictionary of the resource name to resource label mappings
+ under which the evaluation should be done.
+ """
+ def collect_labels(reslabels, s_label, polname):
+ if len(s_label) != 3 or polname != s_label[1]:
+ return False
+ label = s_label[2]
+ if not label in reslabels:
+ reslabels.append(label)
+ return True
+
+ resources = get_domain_resources(dominfo)
+ reslabels = [] # all resource labels
+
+ polname = xspol.get_name()
+ for key, value in resources.items():
+ if key in [ 'vbd', 'tap' ]:
+ for res in resources[key]:
+ try:
+ label = access_control[res]
+ if not collect_labels(reslabels, label, polname):
+ return False
+ except:
+ return False
+ elif key in [ 'vif' ]:
+ for xapi_label in value:
+ label = xapi_label.split(":")
+ if not collect_labels(reslabels, label, polname):
+ return False
+ else:
+ log.error("Unhandled device type: %s" % key)
+ return False
+
+ # Check that all resource labes have a common STE type with the
+ # vmlabel
+ rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels)
+ return rc;
+
+def set_resource_label(resource, policytype, policyref, reslabel, \
+ oreslabel = None):
+ """Assign a label to a resource
+ If the old label (oreslabel) is given, then the resource must have
+ that old label.
+ A resource label may be changed if
+ - the resource is not in use
+ @param resource : The name of a resource, i.e., "phy:/dev/hda"
+ @param policyref : The name of the policy
+ @param reslabel : the resource label within the policy
+ @param oreslabel : optional current resource label
+
+ @rtype: int
+ @return Success (0) or failure value (< 0)
+ """
+ try:
+ resource = unify_resname(resource, mustexist=False)
+ except Exception:
+ return -xsconstants.XSERR_BAD_RESOURCE_FORMAT
+
+ domains = is_resource_in_use(resource)
+ if len(domains) > 0:
+ return -xsconstants.XSERR_RESOURCE_IN_USE
+
+ try:
+ __resfile_lock.acquire()
+ access_control = {}
+ try:
+ access_control = dictio.dict_read("resources", res_label_filename)
+ except:
+ pass
+ if oreslabel:
+ if not access_control.has_key(resource):
+ return -xsconstants.XSERR_BAD_LABEL
+ tmp = access_control[resource]
+ if len(tmp) != 3:
+ return -xsconstants.XSERR_BAD_LABEL
+ if tmp[2] != oreslabel:
+ return -xsconstants.XSERR_BAD_LABEL
+ if reslabel != "":
+ new_entry = { resource : tuple([policytype, policyref, reslabel])}
+ access_control.update(new_entry)
+ else:
+ if access_control.has_key(resource):
+ del access_control[resource]
+ dictio.dict_write(access_control, "resources", res_label_filename)
+ finally:
+ __resfile_lock.release()
+ return xsconstants.XSERR_SUCCESS
+
+def rm_resource_label(resource, oldlabel_xapi):
+ """Remove a resource label from a physical resource
+ @param resource: The name of a resource, i.e., "phy:/dev/hda"
+
+ @rtype: int
+ @return Success (0) or failure value (< 0)
+ """
+ tmp = oldlabel_xapi.split(":")
+ if len(tmp) != 3:
+ return -xsconstants.XSERR_BAD_LABEL_FORMAT
+ otyp, opolicyref, olabel = tmp
+ # Only ACM is supported
+ if otyp != xsconstants.ACM_POLICY_ID and \
+ otyp != xsconstants.INVALID_POLICY_PREFIX + xsconstants.ACM_POLICY_ID:
+ return -xsconstants.XSERR_WRONG_POLICY_TYPE
+ return set_resource_label(resource, "", "", "", olabel)
+
+def get_resource_label_xapi(resource):
+ """Get the assigned resource label of a physical resource
+ in the format used by then Xen-API, i.e., "ACM:xm-test:blue"
+
+ @rtype: string
+ @return the string representing policy type, policy name and label of
+ the resource
+ """
+ res = get_resource_label(resource)
+ return format_resource_label(res)
+
+def format_resource_label(res):
+ if res:
+ if len(res) == 2:
+ return xsconstants.ACM_POLICY_ID + ":" + res[0] + ":" + res[1]
+ if len(res) == 3:
+ return ":".join(res)
+ return ""
+
+def get_resource_label(resource):
+ """Get the assigned resource label of a given resource
+ @param resource: The name of a resource, i.e., "phy:/dev/hda"
+
+ @rtype: list
+ @return tuple of (policy name, resource label), i.e., (xm-test, blue)
+ """
+ try:
+ resource = unify_resname(resource, mustexist=False)
+ except Exception:
+ return []
+
+ reslabel_map = get_labeled_resources()
+
+ if reslabel_map.has_key(resource):
+ return list(reslabel_map[resource])
+ else:
+ #Try to resolve each label entry
+ for key, value in reslabel_map.items():
+ try:
+ if resource == unify_resname(key):
+ return list(value)
+ except:
+ pass
+
+ return []
+
+
+def get_labeled_resources_xapi():
+ """ Get a map of all labeled resource with the labels formatted in the
+ xen-api resource label format.
+ """
+ reslabel_map = get_labeled_resources()
+ for key, labeldata in reslabel_map.items():
+ reslabel_map[key] = format_resource_label(labeldata)
+ return reslabel_map
+
+
+def get_labeled_resources():
+ """Get a map of all labeled resources
+ @rtype: list
+ @return list of labeled resources
+ """
+ try:
+ __resfile_lock.acquire()
+ try:
+ access_control = dictio.dict_read("resources", res_label_filename)
+ except:
+ return {}
+ finally:
+ __resfile_lock.release()
+ return access_control
+
+
+def relabel_domains(relabel_list):
+ """
+ Relabel the given domains to have a new ssidref.
+ @param relabel_list: a list containing tuples of domid, ssidref
+ example: [ [0, 0x00020002] ]
+ """
+ rel_rules = ""
+ for r in relabel_list:
+ log.info("Relabeling domain with domid %d to new ssidref 0x%08x",
+ r[0], r[1])
+ rel_rules += struct.pack("ii", r[0], r[1])
+ try:
+ rc, errors = acm.relabel_domains(rel_rules)
+ except Exception, e:
+ log.info("Error after relabel_domains: %s" % str(e))
+ rc = -xsconstants.XSERR_GENERAL_FAILURE
+ errors = ""
+ if (len(errors) > 0):
+ rc = -xsconstants.XSERR_HV_OP_FAILED
+ return rc, errors
+
+
+def change_acm_policy(bin_pol, del_array, chg_array,
+ vmlabel_map, reslabel_map, cur_acmpol, new_acmpol):
+ """
+ Change the ACM policy of the system by relabeling
+ domains and resources first and doing some access checks.
+ Then update the policy in the hypervisor. If this is all successful,
+ relabel the domains permanently and commit the relabed resources.
+
+ Need to do / check the following:
+ - relabel all resources where there is a 'from' field in
+ the policy. [. NOT DOING THIS: and mark those as unlabeled where the label
+ does not appear in the new policy anymore (deletion) ]
+ - relabel all VMs where there is a 'from' field in the
+ policy and mark those as unlabeled where the label
+ does not appear in the new policy anymore; no running
+ or paused VM may be unlabeled through this
+ - check that under the new labeling conditions the VMs
+ still have access to their resources as before. Unlabeled
+ resources are inaccessible. If this check fails, the
+ update failed.
+ - Attempt changes in the hypervisor; if this step fails,
+ roll back the relabeling of resources and VMs
+ - Make the relabeling of resources and VMs permanent
+ """
+ rc = xsconstants.XSERR_SUCCESS
+
+ domain_label_map = {}
+ new_policyname = new_acmpol.get_name()
+ new_policytype = new_acmpol.get_type_name()
+ cur_policyname = cur_acmpol.get_name()
+ cur_policytype = cur_acmpol.get_type_name()
+ polnew_reslabels = new_acmpol.policy_get_resourcelabel_names()
+ errors=""
+
+ try:
+ __resfile_lock.acquire()
+ mapfile_lock()
+
+ # Get all domains' dominfo.
+ from xen.xend import XendDomain
+ dominfos = XendDomain.instance().list('all')
+
+ log.info("----------------------------------------------")
+ # relabel resources
+
+ access_control = {}
+ try:
+ access_control = dictio.dict_read("resources", res_label_filename)
+ finally:
+ pass
+ for key, labeldata in access_control.items():
+ if len(labeldata) == 2:
+ policy, label = labeldata
+ policytype = xsconstants.ACM_POLICY_ID
+ elif len(labeldata) == 3:
+ policytype, policy, label = labeldata
+ else:
+ return -xsconstants.XSERR_BAD_LABEL_FORMAT, ""
+
+ if policytype != cur_policytype or \
+ policy != cur_policyname:
+ continue
+
+ # label been renamed or deleted?
+ if reslabel_map.has_key(label) and cur_policyname == policy:
+ label = reslabel_map[label]
+ elif label not in polnew_reslabels:
+ policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
+ # Update entry
+ access_control[key] = \
+ tuple([ policytype, new_policyname, label ])
+
+ # All resources have new labels in the access_control map
+ # There may still be labels in there that are invalid now.
+
+ # Do this in memory without writing to disk:
+ # - Relabel all domains independent of whether they are running
+ # or not
+ # - later write back to config files
+ polnew_vmlabels = new_acmpol.policy_get_virtualmachinelabel_names()
+
+ for dominfo in dominfos:
+ sec_lab = dominfo.get_security_label()
+ if not sec_lab:
+ continue
+ policytype, policy, vmlabel = sec_lab.split(":")
+ name = dominfo.getName()
+
+ if policytype != cur_policytype or \
+ policy != cur_policyname:
+ continue
+
+ new_vmlabel = vmlabel
+ if vmlabel_map.has_key(vmlabel):
+ new_vmlabel = vmlabel_map[vmlabel]
+ if new_vmlabel not in polnew_vmlabels:
+ policytype = xsconstants.INVALID_POLICY_PREFIX + policytype
+ new_seclab = "%s:%s:%s" % \
+ (policytype, new_policyname, new_vmlabel)
+
+ domain_label_map[dominfo] = [ sec_lab, new_seclab ]
+
+ if dominfo._stateGet() in (DOM_STATE_PAUSED, DOM_STATE_RUNNING):
+ compatible = __resources_compatible_with_vmlabel(new_acmpol,
+ dominfo,
+ new_vmlabel,
+ access_control)
+ log.info("Domain %s with new label '%s' can access its "
+ "resources? : %s" %
+ (name, new_vmlabel, str(compatible)))
+ log.info("VM labels in new domain: %s" %
+ new_acmpol.policy_get_virtualmachinelabel_names())
+ if not compatible:
+ return (-xsconstants.XSERR_RESOURCE_ACCESS, "")
+
+ rc, errors = hv_chg_policy(bin_pol, del_array, chg_array)
+ if rc == 0:
+ # Write the relabeled resources back into the file
+ dictio.dict_write(access_control, "resources", res_label_filename)
+ # Properly update all VMs to their new labels
+ for dominfo, labels in domain_label_map.items():
+ sec_lab, new_seclab = labels
+ if sec_lab != new_seclab:
+ log.info("Updating domain %s to new label '%s'." % \
+ (sec_lab, new_seclab))
+ # This better be working!
+ dominfo.set_security_label(new_seclab,
+ sec_lab,
+ new_acmpol)
+ finally:
+ log.info("----------------------------------------------")
+ mapfile_unlock()
+ __resfile_lock.release()
+
+ return rc, errors
+
+def parse_security_label(security_label):
+ tmp = security_label.split(":")
+ if len(tmp) != 3:
+ return ""
+ else:
+ return security_label
+
+def set_security_label(policy, label):
+ policytype = xsconstants.ACM_POLICY_ID
+ if label != "" and policy != "":
+ return "%s:%s:%s" % (policytype, policy, label)
+ else:
+ return ""
+
+def ssidref2security_label(ssidref):
+ from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+ return XSPolicyAdminInstance().ssidref_to_vmlabel(ssidref)
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/dummy/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/__init__.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,1 @@
+
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/dummy/dummy.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/dummy.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,53 @@
+import sys
+
+class XSMError(Exception):
+ def __init__(self,value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+policy_dir_prefix = "";
+active_policy = "";
+NULL_SSIDREF = 0;
+
+def err(msg):
+ """Raise XSM-dummy exception.
+ """
+ sys.stderr.write("XSM-dummyError: " + msg + "\n")
+ raise XSMError(msg)
+
+def on():
+ return 0
+
+def ssidref2label(ssidref):
+ return 0
+
+def label2ssidref(label, policy, type):
+ return 0
+
+def res_security_check(resource, domain_label):
+ return 1
+
+def get_res_security_details(resource):
+ return ("","","")
+
+def get_res_label(resource):
+ return ("","")
+
+def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label):
+ return 1
+
+def parse_security_label(security_label):
+ return ""
+
+def calc_dom_ssidref_from_info(info):
+ return ""
+
+def set_security_label(policy, label):
+ return ""
+
+def ssidref2security_label(ssidref):
+ return ""
+
+def has_authorization(ssidref):
+ return True
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/flask/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/__init__.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,1 @@
+
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/flask/flask.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/flask.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,37 @@
+import sys
+from xen.lowlevel import flask
+from xen.xend import sxp
+
+def err(msg):
+ """Raise XSM-Flask exception.
+ """
+ sys.stderr.write("XSM-FlaskError: " + msg + "\n")
+ raise XSMError(msg)
+
+def on():
+ return 1
+
+def ssidref2label(ssidref):
+ try:
+ return flask.flask_sid_to_context(ssidref)
+ except:
+ return ""
+
+def label2ssidref(label, policy, type):
+ try:
+ return flask.flask_context_to_sid(label)
+ except:
+ return ""
+
+def parse_security_label(security_label):
+ return security_label
+
+def calc_dom_ssidref_from_info(info):
+ ssidref = label2ssidref(info['security_label'], "", "")
+ return ssidref
+
+def set_security_label(policy, label):
+ return label
+
+def ssidref2security_label(ssidref):
+ return ssidref2label(ssidref)
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/util/xsm/xsm_core.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/xsm_core.py Fri Aug 31 11:37:20 2007 +0100
@@ -0,0 +1,7 @@
+import sys
+import xen.util.xsm.dummy.dummy as dummy
+
+def xsm_init(self):
+ for op in dir(dummy):
+ if not hasattr(self, op):
+ setattr(self, op, getattr(dummy, op, None))
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/XendConfig.py Fri Aug 31 11:37:20 2007 +0100
@@ -30,7 +30,6 @@ from xen.xend.XendConstants import DOM_S
from xen.xend.XendConstants import DOM_STATE_HALTED
from xen.xend.server.netif import randomMAC
from xen.util.blkif import blkdev_name_to_number
-from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
from xen.util import xsconstants

log = logging.getLogger("xend.XendConfig")
@@ -433,7 +432,8 @@ class XendConfig(dict):
self['cpu_time'] = dominfo['cpu_time']/1e9
if dominfo.get('ssidref'):
ssidref = int(dominfo.get('ssidref'))
- self['security_label'] = XSPolicyAdminInstance().ssidref_to_vmlabel(ssidref)
+ import xen.util.xsm.xsm as security
+ self['security_label'] = security.ssidref2security_label(ssidref)

self['shutdown_reason'] = dominfo['shutdown_reason']

@@ -651,7 +651,6 @@ class XendConfig(dict):
# ['ssidref', 196611]]
policy = ""
label = ""
- policytype = xsconstants.ACM_POLICY_ID
for idx in range(0, len(secinfo)):
if secinfo[idx][0] == "access_control":
for aidx in range(1, len(secinfo[idx])):
@@ -659,9 +658,10 @@ class XendConfig(dict):
policy = secinfo[idx][aidx][1]
if secinfo[idx][aidx][0] == "label":
label = secinfo[idx][aidx][1]
- if label != "" and policy != "":
- cfg['security_label'] = "%s:%s:%s" % \
- (policytype, policy, label)
+ import xen.util.xsm.xsm as security
+ cfg['security_label'] = \
+ security.set_security_label(policy, label)
+ if not sxp.child_value(sxp_cfg, 'security_label'):
del cfg['security']

old_state = sxp.child_value(sxp_cfg, 'state')
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Fri Aug 31 11:37:20 2007 +0100
@@ -36,7 +36,7 @@ import xen.lowlevel.xc
import xen.lowlevel.xc
from xen.util import asserts
from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype
-from xen.util import security
+import xen.util.xsm.xsm as security

from xen.xend import balloon, sxp, uuid, image, arch, osdep
from xen.xend import XendOptions, XendNode, XendConfig
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/XendVDI.py
--- a/tools/python/xen/xend/XendVDI.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/XendVDI.py Fri Aug 31 11:37:20 2007 +0100
@@ -23,7 +23,8 @@ import os

from xen.util.xmlrpclib2 import stringify
from xmlrpclib import dumps, loads
-from xen.util import security, xsconstants
+from xen.util import xsconstants
+import xen.util.xsm.xsm as security
from xen.xend.XendError import SecurityError

KB = 1024
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/XendXSPolicy.py
--- a/tools/python/xen/xend/XendXSPolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/XendXSPolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,8 @@ from xen.xend.XendBase import XendBase
from xen.xend.XendBase import XendBase
from xen.xend.XendError import *
from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
-from xen.util import xsconstants, security
+from xen.util import xsconstants
+import xen.util.xsm.xsm as security
import base64

log = logging.getLogger("xend.XendXSPolicy")
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/XendXSPolicyAdmin.py
--- a/tools/python/xen/xend/XendXSPolicyAdmin.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/XendXSPolicyAdmin.py Fri Aug 31 11:37:20 2007 +0100
@@ -22,7 +22,8 @@ from xml.dom import minidom, Node

from xen.xend.XendLogging import log
from xen.xend import uuid
-from xen.util import security, xsconstants, dictio, bootloader
+from xen.util import xsconstants, dictio, bootloader
+import xen.util.xsm.acm.acm as security
from xen.util.xspolicy import XSPolicy
from xen.util.acmpolicy import ACMPolicy
from xen.xend.XendError import SecurityError
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/server/blkif.py
--- a/tools/python/xen/xend/server/blkif.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/server/blkif.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,7 @@ import string
import string

from xen.util import blkif
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xend.XendError import VmError
from xen.xend.server.DevController import DevController

diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xend/server/netif.py
--- a/tools/python/xen/xend/server/netif.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xend/server/netif.py Fri Aug 31 11:37:20 2007 +0100
@@ -27,8 +27,8 @@ from xen.xend import XendOptions
from xen.xend import XendOptions
from xen.xend.server.DevController import DevController
from xen.xend.XendError import VmError
-from xen.util import security
from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+import xen.util.xsm.xsm as security

from xen.xend.XendLogging import log

diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/addlabel.py
--- a/tools/python/xen/xm/addlabel.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/addlabel.py Fri Aug 31 11:37:20 2007 +0100
@@ -23,7 +23,7 @@ import sys
import sys

from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xm.opts import OptionError
from xen.util import xsconstants
from xen.xm import main as xm_main
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/cfgbootpolicy.py
--- a/tools/python/xen/xm/cfgbootpolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/cfgbootpolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -26,11 +26,11 @@ import shutil
import shutil
import string
import re
-from xen.util.security import err
-from xen.util.security import policy_dir_prefix, xen_title_re
-from xen.util.security import boot_filename, altboot_filename
-from xen.util.security import any_title_re, xen_kernel_re, any_module_re
-from xen.util.security import empty_line_re, binary_name_re, policy_name_re
+from xen.util.xsm.xsm import err
+from xen.util.xsm.xsm import policy_dir_prefix, xen_title_re
+from xen.util.xsm.xsm import boot_filename, altboot_filename
+from xen.util.xsm.xsm import any_title_re, xen_kernel_re, any_module_re
+from xen.util.xsm.xsm import empty_line_re, binary_name_re, policy_name_re
from xen.util import xsconstants
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/create.py Fri Aug 31 11:37:20 2007 +0100
@@ -33,7 +33,7 @@ import xen.xend.XendClient
import xen.xend.XendClient
from xen.xend.XendBootloader import bootloader
from xen.util import blkif
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm

from xen.xm.opts import *
@@ -1221,7 +1221,7 @@ def config_security_check(config, verbos
if verbose:
print " %s: PERMITTED" % (resource)

- except security.ACMError:
+ except security.XSMError:
print " %s: DENIED" % (resource)
(poltype, res_label, res_policy) = security.get_res_label(resource)
if not res_label:
@@ -1243,7 +1243,7 @@ def create_security_check(config):
passed = 1
else:
print "Checking resources: (skipped)"
- except security.ACMError:
+ except security.XSMError:
sys.exit(-1)

return passed
@@ -1300,7 +1300,7 @@ def main(argv):
map(lambda vm_ref: server.xenapi.VM.start(vm_ref, 0), vm_refs)
elif not opts.is_xml:
if not create_security_check(config):
- raise security.ACMError(
+ raise security.XSMError(
'Security Configuration prevents domain from starting')
dom = make_domain(opts, config)

diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/dry-run.py
--- a/tools/python/xen/xm/dry-run.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/dry-run.py Fri Aug 31 11:37:20 2007 +0100
@@ -19,7 +19,7 @@
"""Tests the security settings for a domain and its resources.
"""
import sys
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xm import create
from xen.xend import sxp
from xen.xm.opts import OptionError
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/dumppolicy.py
--- a/tools/python/xen/xm/dumppolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/dumppolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -18,7 +18,7 @@
"""Display currently enforced policy (low-level hypervisor representation).
"""
import sys
-from xen.util.security import ACMError, err, dump_policy
+from xen.util.xsm.xsm import XSMError, err, dump_policy
from xen.xm.opts import OptionError

def help():
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/getlabel.py
--- a/tools/python/xen/xm/getlabel.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/getlabel.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,7 @@
"""
import sys, os, re
from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.util import xsconstants
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
@@ -62,7 +62,7 @@ def get_resource_label(resource):
"Please relabel the resource.")
print policytype+":"+policy+":"+label
else:
- raise security.ACMError("Resource not labeled")
+ raise security.XSMError("Resource not labeled")


def get_domain_label(configfile):
@@ -95,7 +95,7 @@ def get_domain_label(configfile):

# send error message if we didn't find anything
if acline == "":
- raise security.ACMError("Domain not labeled")
+ raise security.XSMError("Domain not labeled")

# print out the label
(title, data) = acline.split("=", 1)
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/labels.py
--- a/tools/python/xen/xm/labels.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/labels.py Fri Aug 31 11:37:20 2007 +0100
@@ -21,8 +21,8 @@ import sys
import sys
import traceback
import string
-from xen.util.security import ACMError, err, list_labels, active_policy
-from xen.util.security import vm_label_re, res_label_re, all_label_re
+from xen.util.xsm.xsm import XSMError, err, list_labels, active_policy
+from xen.util.xsm.xsm import vm_label_re, res_label_re, all_label_re
from xen.xm.opts import OptionError
from xen.util.acmpolicy import ACMPolicy
from xen.util import xsconstants
@@ -78,7 +78,7 @@ def labels(policy, ptype):
for label in labels:
print label

- except ACMError:
+ except XSMError:
sys.exit(-1)
except:
traceback.print_exc(limit = 1)
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/loadpolicy.py
--- a/tools/python/xen/xm/loadpolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/loadpolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,7 @@
"""
import sys
import traceback
-from xen.util.security import ACMError, err, load_policy
+from xen.util.xsm.xsm import XSMError, err, load_policy
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
from xen.util import xsconstants
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/main.py Fri Aug 31 11:37:20 2007 +0100
@@ -49,7 +49,8 @@ from xen.xm.opts import OptionError, Opt
from xen.xm.opts import OptionError, Opts, wrap, set_true
from xen.xm import console
from xen.util.xmlrpcclient import ServerProxy
-from xen.util.security import ACMError
+import xen.util.xsm.xsm as security
+from xen.util.xsm.xsm import XSMError
from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY

import XenAPI
@@ -872,12 +873,7 @@ def parse_doms_info(info):
}

security_label = get_info('security_label', str, '')
- tmp = security_label.split(":")
- if len(tmp) != 3:
- seclabel = ""
- else:
- seclabel = security_label
- parsed_info['seclabel'] = seclabel
+ parsed_info['seclabel'] = security.parse_security_label(security_label)

if serverType == SERVER_XEN_API:
parsed_info['mem'] = get_info('memory_actual', int, 0) / 1024
@@ -935,14 +931,14 @@ def xm_brief_list(doms):
print format % d

def xm_label_list(doms):
- print '%-32s %5s %5s %5s %10s %9s %-8s' % \
+ print '%-40s %3s %5s %5s %10s %9s %-10s' % \
('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
-
+
output = []
- format = '%(name)-32s %(domid)5s %(mem)5d %(vcpus)5d %(state)10s ' \
- '%(cpu_time)8.1f %(seclabel)9s'
-
- from xen.util import security
+ format = '%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
+ '%(cpu_time)8.1f %(seclabel)10s'
+
+ import xen.util.xsm.xsm as security

for dom in doms:
d = parse_doms_info(dom)
@@ -2580,12 +2576,12 @@ def _run_cmd(cmd, cmd_name, args):
print e.usage
except XenAPIUnsupportedException, e:
err(str(e))
- except ACMError, e:
+ except XSMError, e:
err(str(e))
except Exception, e:
if serverType != SERVER_XEN_API:
- from xen.util import security
- if isinstance(e, security.ACMError):
+ import xen.util.xsm.xsm as security
+ if isinstance(e, security.XSMError):
err(str(e))
return False, 1
print "Unexpected error:", sys.exc_info()[0]
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/makepolicy.py
--- a/tools/python/xen/xm/makepolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/makepolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -19,7 +19,7 @@
"""
import sys
import traceback
-from xen.util.security import ACMError, err, make_policy
+from xen.util.xsm.xsm import ACMError, err, make_policy
from xen.util import xsconstants
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/resources.py
--- a/tools/python/xen/xm/resources.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/resources.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,7 @@
"""
import sys
from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.util import xsconstants
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/rmlabel.py
--- a/tools/python/xen/xm/rmlabel.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/rmlabel.py Fri Aug 31 11:37:20 2007 +0100
@@ -20,7 +20,7 @@
"""
import sys, os, re
from xen.util import dictio
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xm.opts import OptionError
from xen.xm import main as xm_main
from xen.xm.main import server
@@ -108,7 +108,7 @@ def rm_domain_label(configfile):

# send error message if we didn't find anything to remove
if not removed:
- raise security.ACMError('Domain not labeled')
+ raise security.XSMError('Domain not labeled')

# write the data back out to the file
fd = open(fil, "wb")
diff -r 6c8c934b235c -r 993655d24b55 tools/python/xen/xm/setpolicy.py
--- a/tools/python/xen/xm/setpolicy.py Fri Aug 31 11:31:18 2007 +0100
+++ b/tools/python/xen/xm/setpolicy.py Fri Aug 31 11:37:20 2007 +0100
@@ -26,7 +26,7 @@ from xen.util import xsconstants
from xen.util import xsconstants
from xen.util.acmpolicy import ACMPolicy
from xen.xm.opts import OptionError
-from xen.util.security import policy_dir_prefix
+from xen.util.xsm.acm.acm import policy_dir_prefix
from xen.xm import main as xm_main
from xen.xm.main import server


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