diff -r 93a0c2864048 -r 88b19079a09d tools/Makefile --- a/tools/Makefile Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/Makefile Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/flask/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/flask/Makefile Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/flask/libflask/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/flask/libflask/Makefile Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/flask/libflask/flask_op.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/flask/libflask/flask_op.c Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,100 @@ +/* + * + * Authors: Michael LeMay, + * George Coker, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +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 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,46 @@ +/* + * + * Authors: Michael LeMay, + * George Coker, + * + * 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 93a0c2864048 -r 88b19079a09d tools/flask/loadpolicy/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/flask/loadpolicy/Makefile Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/flask/loadpolicy/loadpolicy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/flask/loadpolicy/loadpolicy.c Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,130 @@ +/* + * + * Authors: Michael LeMay, + * George Coker, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define USE_MMAP + +static void usage (int argCnt, const char *args[]) +{ + fprintf(stderr, "Usage: %s \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 93a0c2864048 -r 88b19079a09d tools/misc/xenperf.c --- a/tools/misc/xenperf.c Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/misc/xenperf.c Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/Makefile --- a/tools/python/Makefile Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/Makefile Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/setup.py --- a/tools/python/setup.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/setup.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,139 @@ +/****************************************************************************** + * flask.c + * + * Authors: George Coker, + * Michael LeMay, + * + * + * 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 +#include + +#include + +#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 93a0c2864048 -r 88b19079a09d tools/python/xen/util/acmpolicy.py --- a/tools/python/xen/util/acmpolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/util/acmpolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 + "/" @@ -1233,8 +1234,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 93a0c2864048 -r 88b19079a09d tools/python/xen/util/security.py --- a/tools/python/xen/util/security.py Thu Aug 09 17:42:13 2007 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1265 +0,0 @@ -#=========================================================================== -# 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 -# Author: Stefan Berger -#============================================================================ - -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 diff -r 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,2 @@ + + diff -r 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,1 @@ + diff -r 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -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 +# Author: Stefan Berger +#============================================================================ + +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 tmp[2] + +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 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,1 @@ + diff -r 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -0,0 +1,1 @@ + diff -r 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d 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 Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/XendConfig.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/XendDomainInfo.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/XendVDI.py --- a/tools/python/xen/xend/XendVDI.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/XendVDI.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/XendXSPolicy.py --- a/tools/python/xen/xend/XendXSPolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/XendXSPolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/XendXSPolicyAdmin.py --- a/tools/python/xen/xend/XendXSPolicyAdmin.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/XendXSPolicyAdmin.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/server/blkif.py --- a/tools/python/xen/xend/server/blkif.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/server/blkif.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xend/server/netif.py --- a/tools/python/xen/xend/server/netif.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xend/server/netif.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/addlabel.py --- a/tools/python/xen/xm/addlabel.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/addlabel.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/cfgbootpolicy.py --- a/tools/python/xen/xm/cfgbootpolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/cfgbootpolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/create.py --- a/tools/python/xen/xm/create.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/create.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 * @@ -1220,7 +1220,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: @@ -1242,7 +1242,7 @@ def create_security_check(config): passed = 1 else: print "Checking resources: (skipped)" - except security.ACMError: + except security.XSMError: sys.exit(-1) return passed @@ -1299,7 +1299,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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/dry-run.py --- a/tools/python/xen/xm/dry-run.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/dry-run.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/dumppolicy.py --- a/tools/python/xen/xm/dumppolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/dumppolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/getlabel.py --- a/tools/python/xen/xm/getlabel.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/getlabel.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/labels.py --- a/tools/python/xen/xm/labels.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/labels.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/loadpolicy.py --- a/tools/python/xen/xm/loadpolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/loadpolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/main.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 @@ -871,13 +872,9 @@ def parse_doms_info(info): 'up_time' : up_time } + import xen.util.xsm.xsm as security security_label = get_info('security_label', str, '') - tmp = security_label.split(":") - if len(tmp) != 3: - seclabel = "" - else: - seclabel = tmp[2] - 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 +932,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) @@ -2579,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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/makepolicy.py --- a/tools/python/xen/xm/makepolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/makepolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/resources.py --- a/tools/python/xen/xm/resources.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/resources.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/rmlabel.py --- a/tools/python/xen/xm/rmlabel.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/rmlabel.py Mon Aug 13 12:57:55 2007 -0400 @@ -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 93a0c2864048 -r 88b19079a09d tools/python/xen/xm/setpolicy.py --- a/tools/python/xen/xm/setpolicy.py Thu Aug 09 17:42:13 2007 -0400 +++ b/tools/python/xen/xm/setpolicy.py Mon Aug 13 12:57:55 2007 -0400 @@ -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