[prev in list] [next in list] [prev in thread] [next in thread]
List: xense-devel
Subject: [Xen-devel] [Xense-devel] [PATCH] [3/4] Flask XSM tools
From: "George S. Coker, II" <gscoker () alpha ! ncsc ! mil>
Date: 2006-12-20 14:08:58
Message-ID: 1166623739.4824.266.camel () moss-walleye ! epoch ! ncsc ! mil
[Download RAW message or body]
This patch implements the Flask tools for the xen control plane (xm &
xend). The patch also refactors the ACM toolchain so that a common
security API (based on the existing ACM toolchain) is exported to xm and
xend.
To create a domain with the Flask module, add the following (for
example) to a domain's configuration file
access_control = ["policy=,label=system_u:object_r:domU_t"]
This will cause a domain to be created with the label
"system_u:object_r:domU_t". Flask does not use the policy value in the
access_control structure.
Signed-off-by: George Coker <gscoker@alpha.ncsc.mil>
["tools-xsm-flask-121906-xen-unstable.diff" (tools-xsm-flask-121906-xen-unstable.diff)]
diff -r 12923ba929c8 -r 0655af4eae49 tools/Makefile
--- a/tools/Makefile Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/Makefile Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/libxc/xc_acm.c
--- a/tools/libxc/xc_acm.c Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/libxc/xc_acm.c Tue Dec 19 21:50:31 2006 -0500
@@ -19,7 +19,7 @@ int xc_acm_op(int xc_handle, int cmd, vo
int ret = -1;
DECLARE_HYPERCALL;
- hypercall.op = __HYPERVISOR_acm_op;
+ hypercall.op = __HYPERVISOR_xsm_op;
hypercall.arg[0] = cmd;
hypercall.arg[1] = (unsigned long) arg;
diff -r 12923ba929c8 -r 0655af4eae49 tools/misc/xenperf.c
--- a/tools/misc/xenperf.c Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/misc/xenperf.c Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/python/Makefile
--- a/tools/python/Makefile Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/Makefile Tue Dec 19 21:50:31 2006 -0500
@@ -1,11 +1,32 @@ 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
+
+xen/util/xsm/xsm.py:
+ @(set -e; \
+ echo "XEN_SECURITY_MODULE = \""$(XEN_SECURITY_MODULE)"\""; \
+ echo "";\
+ echo "if XEN_SECURITY_MODULE == 'flask':"; \
+ echo " from xen.util.xsm.flask.flask import *"; \
+ echo "elif XEN_SECURITY_MODULE == 'acm':"; \
+ echo " from xen.util.xsm.acm.acm import *"; \
+ echo "else:"; \
+ echo " from xen.util.xsm.dummy.dummy import *"; \
+ echo "") >$@
.PHONY: all
all: build
.PHONY: build
build:
+ $(MAKE) xen/util/xsm/xsm.py
CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py build
.PHONY: install
@@ -23,4 +44,5 @@ test:
.PHONY: clean
clean:
+ rm xen/util/xsm/xsm.py
rm -rf build *.pyc *.pyo *.o *.a *~
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/setup.py
--- a/tools/python/setup.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/setup.py Tue Dec 19 21:50:31 2006 -0500
@@ -1,6 +1,7 @@
from distutils.core import setup, Extension
import os
+
XEN_ROOT = "../.."
@@ -37,12 +38,24 @@ 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" ] +
+ [ "/tools/flask/libflask/include" ],
+ library_dirs = library_dirs + [ "/tools/flask/libflask" ],
+ libraries = libraries + [ "flask" ],
+ sources = [ "xen/lowlevel/flask/flask.c" ])
+
setup(name = 'xen',
version = '3.0',
description = 'Xen',
packages = ['xen',
'xen.lowlevel',
'xen.util',
+ 'xen.util.xsm',
+ 'xen.util.xsm.flask',
+ 'xen.util.xsm.acm',
+ 'xen.util.xsm.dummy',
'xen.xend',
'xen.xend.server',
'xen.xend.xenstore',
@@ -56,7 +69,7 @@ setup(name = 'xen',
'xen.xm.tests'
],
ext_package = "xen.lowlevel",
- ext_modules = [ xc, xs, acm ]
+ ext_modules = [ xc, xs, acm, flask ],
)
os.chdir('logging')
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/sv/CreateDomain.py
--- a/tools/python/xen/sv/CreateDomain.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/sv/CreateDomain.py Tue Dec 19 21:50:31 2006 -0500
@@ -178,6 +178,7 @@ class CreateFinish( Sheet ):
vals.console = None
vals.ramdisk = None
vals.ssidref = -1
+ vals.context = None
vals.bootloader = None
vals.usb = []
vals.acpi = []
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xend/XendDomain.py Tue Dec 19 21:50:31 2006 -0500
@@ -45,7 +45,8 @@ from xen.xend.XendDevices import XendDev
from xen.xend.xenstore.xstransact import xstransact
from xen.xend.xenstore.xswatch import xswatch
-from xen.util import mkdir, security
+from xen.util import mkdir
+import xen.util.xsm.xsm as security
from xen.xend import uuid
xc = xen.lowlevel.xc.xc()
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xend/XendDomainInfo.py Tue Dec 19 21:50:31 2006 -0500
@@ -35,7 +35,7 @@ import xen.lowlevel.xc
import xen.lowlevel.xc
from xen.util import asserts
from xen.util.blkif import blkdev_uname_to_file
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.xend import balloon, sxp, uuid, image, arch
from xen.xend import XendRoot, XendNode, XendConfig
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xend/server/blkif.py
--- a/tools/python/xen/xend/server/blkif.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xend/server/blkif.py Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/addlabel.py
--- a/tools/python/xen/xm/addlabel.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/addlabel.py Tue Dec 19 21:50:31 2006 -0500
@@ -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
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/cfgbootpolicy.py
--- a/tools/python/xen/xm/cfgbootpolicy.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/cfgbootpolicy.py Tue Dec 19 21:50:31 2006 -0500
@@ -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.xm.opts import OptionError
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/create.py Tue Dec 19 21:50:31 2006 -0500
@@ -31,7 +31,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.opts import *
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/dry-run.py
--- a/tools/python/xen/xm/dry-run.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/dry-run.py Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/dumppolicy.py
--- a/tools/python/xen/xm/dumppolicy.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/dumppolicy.py Tue Dec 19 21:50:31 2006 -0500
@@ -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 ACMError, err, dump_policy
from xen.xm.opts import OptionError
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/getlabel.py
--- a/tools/python/xen/xm/getlabel.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/getlabel.py Tue Dec 19 21:50:31 2006 -0500
@@ -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
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/labels.py
--- a/tools/python/xen/xm/labels.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/labels.py Tue Dec 19 21:50:31 2006 -0500
@@ -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 ACMError, 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
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/loadpolicy.py
--- a/tools/python/xen/xm/loadpolicy.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/loadpolicy.py Tue Dec 19 21:50:31 2006 -0500
@@ -20,7 +20,7 @@
"""
import sys
import traceback
-from xen.util.security import ACMError, err, load_policy
+from xen.util.xsm.xsm import ACMError, err, load_policy
from xen.xm.opts import OptionError
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/main.py Tue Dec 19 21:50:31 2006 -0500
@@ -45,7 +45,7 @@ from xen.xend.XendConstants import *
from xen.xm.opts import OptionError, Opts, wrap, set_true
from xen.xm import console
-from xen.util import security
+import xen.util.xsm.xsm as security
from xen.util.xmlrpclib2 import ServerProxy
import XenAPI
@@ -676,12 +676,12 @@ def xm_brief_list(doms):
print format % d
def xm_label_list(doms):
- print '%-32s %3s %5s %5s %5s %9s %-8s' % \
+ print '%-40s %3s %5s %5s %10s %9s %-10s' % \
('Name', 'ID', 'Mem', 'VCPUs', 'State', 'Time(s)', 'Label')
output = []
- format = '%(name)-32s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
- '%(cpu_time)8.1f %(seclabel)9s'
+ format = '%(name)-40s %(domid)3s %(mem)5d %(vcpus)5d %(state)10s ' \
+ '%(cpu_time)8.1f %(seclabel)10s'
for dom in doms:
d = parse_doms_info(dom)
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/makepolicy.py
--- a/tools/python/xen/xm/makepolicy.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/makepolicy.py Tue Dec 19 21:50:31 2006 -0500
@@ -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.xm.opts import OptionError
def usage():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/resources.py
--- a/tools/python/xen/xm/resources.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/resources.py Tue Dec 19 21:50:31 2006 -0500
@@ -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.xm.opts import OptionError
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/xm/rmlabel.py
--- a/tools/python/xen/xm/rmlabel.py Sat Dec 16 11:54:25 2006 -0500
+++ b/tools/python/xen/xm/rmlabel.py Tue Dec 19 21:50:31 2006 -0500
@@ -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
def help():
diff -r 12923ba929c8 -r 0655af4eae49 tools/flask/Makefile
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/Makefile Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/flask/libflask/Makefile
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/libflask/Makefile Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,93 @@
+
+INSTALL = install
+INSTALL_PROG = $(INSTALL) -m0755
+INSTALL_DATA = $(INSTALL) -m0644
+INSTALL_DIR = $(INSTALL) -d -m0755
+
+MAJOR = 3.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)
+# Define this to make it possible to run valgrind on code linked with these
+# libraries.
+#CFLAGS += -DVALGRIND -O0 -ggdb3
+
+# 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: check-for-zlib mk-symlinks
+ $(MAKE) $(LIB)
+
+.PHONY: check-for-zlib
+check-for-zlib:
+ @if [ ! -e /usr/include/zlib.h ]; then \
+ echo "***********************************************************"; \
+ echo "ERROR: install zlib header files (http://www.gzip.org/zlib)"; \
+ echo "***********************************************************"; \
+ false; \
+ fi
+
+.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
+
+.PHONY: rpm
+rpm: build
+ rm -rf staging
+ mkdir staging
+ mkdir staging/i386
+ rpmbuild --define "staging$$PWD/staging" --define '_builddir.' \
+ --define "_rpmdir$$PWD/staging" -bb rpm.spec
+ mv staging/i386/*.rpm .
+ rm -rf staging
+
+# 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 12923ba929c8 -r 0655af4eae49 tools/flask/libflask/flask_op.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/libflask/flask_op.c Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,104 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <xc_private.h>
+
+#include "flask_op.h"
+
+int flask_load(int xc_handle, char *buf, int size)
+{
+ int err;
+ int cmd;
+ flask_op_t op;
+
+ cmd = FLASK_LOAD;
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = do_flask_op(xc_handle, cmd, &op)) != 0 )
+ return err;
+
+ return 0;
+}
+
+int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid)
+{
+ int err;
+ int cmd;
+ flask_op_t op;
+
+ cmd = FLASK_CONTEXT_TO_SID;
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = do_flask_op(xc_handle, cmd, &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;
+ int cmd;
+ flask_op_t op;
+
+ cmd = FLASK_SID_TO_CONTEXT;
+ op.buf = buf;
+ op.size = size;
+
+ snprintf(buf, size, "%u", sid);
+
+ if ( (err = do_flask_op(xc_handle, cmd, &op)) != 0 )
+ return err;
+
+ return 0;
+}
+
+int do_flask_op(int xc_handle, int cmd, flask_op_t *op)
+{
+ int ret = -1;
+ DECLARE_HYPERCALL;
+
+ hypercall.op = __HYPERVISOR_xsm_op;
+ hypercall.arg[0] = cmd;
+ hypercall.arg[1] = (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 12923ba929c8 -r 0655af4eae49 tools/flask/libflask/include/flask_op.h
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/libflask/include/flask_op.h Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,49 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef UTIL_FLASK_OP_H
+#define UTIL_FLASK_OP_H
+
+struct flask_op {
+ int size;
+ char *buf;
+};
+
+
+struct flask_op_t;
+typedef struct flask_op flask_op_t;
+
+#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
+
+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, int cmd, flask_op_t *op);
+
+#endif
diff -r 12923ba929c8 -r 0655af4eae49 tools/flask/loadpolicy/Makefile
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/Makefile Tue Dec 19 21:50:31 2006 -0500
@@ -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 12923ba929c8 -r 0655af4eae49 tools/flask/loadpolicy/loadpolicy.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/flask/loadpolicy/loadpolicy.c Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,117 @@
+/*
+ *
+ * Authors: Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ * George Coker, <gscoker@alpha.ncsc.mil>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <xenctrl.h>
+#include <flask_op.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#define USE_MMAP
+
+static void usage (int argCnt, const char *args[]) {
+ fprintf(stderr, "Usage: %s <policy.file>\n", args[0]);
+
+ exit(1);
+}
+
+int main (int argCnt, const char *args[]) {
+ const char *polFName;
+ int polFd = 0;
+ void *polMem = NULL;
+ void *polMemCp = NULL;
+ struct stat info;
+ int ret;
+ int xch = 0;
+
+ if (argCnt != 2)
+ usage(argCnt, args);
+
+ polFName = args[1];
+ polFd = open(polFName, O_RDONLY);
+ if (polFd < 0) {
+ fprintf(stderr, "Error occurred opening policy file '%s': %s\n",
+ polFName, strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = stat(polFName, &info);
+ if (ret < 0) {
+ fprintf(stderr, "Error occurred retrieving information about"
+ "policy file '%s': %s\n", polFName, strerror(errno));
+ goto cleanup;
+ }
+
+ polMemCp = malloc(info.st_size);
+
+#ifdef USE_MMAP
+ polMem = mmap(NULL, info.st_size, PROT_READ, MAP_SHARED, polFd, 0);
+ if (!polMem) {
+ fprintf(stderr, "Error occurred mapping policy file in memory: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ xch = xc_interface_open();
+ if (xch < 0) {
+ fprintf(stderr, "Unable to create interface to xenctrl: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ memcpy(polMemCp, polMem, info.st_size);
+#else
+ ret = read(polFd, polMemCp, info.st_size);
+ if (ret < 0) {
+ fprintf(stderr, "Unable to read new Flask policy file: %s\n",
+ strerror(errno));
+ goto cleanup;
+ } else {
+ printf("Read %d bytes from policy file '%s'.\n", ret, polFName);
+ }
+#endif
+
+ ret = flask_load(xch, polMemCp, info.st_size);
+ if (ret < 0) {
+ errno = -ret;
+ fprintf(stderr, "Unable to load new Flask policy: %s\n",
+ strerror(errno));
+ ret = -1;
+ goto cleanup;
+ } else {
+ printf("Successfully loaded policy.\n");
+ }
+
+done:
+ if (polMemCp)
+ free(polMemCp);
+ if (polMem) {
+ ret = munmap(polMem, info.st_size);
+ if (ret < 0)
+ fprintf(stderr, "Unable to unmap policy memory: %s\n", strerror(errno));
+ }
+ if (polFd)
+ close(polFd);
+ if (xch)
+ xc_interface_close(xch);
+
+ return ret;
+
+cleanup:
+ goto done;
+}
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/lowlevel/flask/flask.c
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/lowlevel/flask/flask.c Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,139 @@
+/******************************************************************************
+ * flask.c
+ *
+ * Authors: George Coker, <gscoker@alpha.ncsc.mil>
+ * Michael LeMay, <mdlemay@epoch.ncsc.mil>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ */
+
+#include <Python.h>
+#include <xenctrl.h>
+
+#include <flask_op.h>
+
+#define PKG "xen.lowlevel.flask"
+#define CLS "flask"
+
+#define CTX_LEN 1024
+
+static PyObject *xc_error_obj;
+
+typedef struct {
+ PyObject_HEAD;
+ int xc_handle;
+} XcObject;
+
+static PyObject *pyflask_context_to_sid(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ int xc_handle;
+ char *ctx;
+ char *buf;
+ uint32_t len;
+ uint32_t sid;
+ int ret;
+
+ static char *kwd_list[] = { "context", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "s", kwd_list,
+ &ctx) )
+ return NULL;
+
+ len = strlen(ctx);
+
+ buf = malloc(len);
+ if (!buf) {
+ errno = -ENOMEM;
+ PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ memcpy(buf, ctx, len);
+
+ xc_handle = xc_interface_open();
+ if (xc_handle < 0) {
+ errno = xc_handle;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ ret = flask_context_to_sid(xc_handle, buf, len, &sid);
+
+ xc_interface_close(xc_handle);
+
+ free(buf);
+
+ if ( ret != 0 ) {
+ errno = -ret;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ return PyInt_FromLong(sid);
+}
+
+static PyObject *pyflask_sid_to_context(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ int xc_handle;
+ uint32_t sid;
+ char ctx[CTX_LEN];
+ uint32_t ctx_len = CTX_LEN;
+ int ret;
+
+ static char *kwd_list[] = { "sid", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
+ &sid) )
+ return NULL;
+
+ xc_handle = xc_interface_open();
+ if (xc_handle < 0) {
+ errno = xc_handle;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ ret = flask_sid_to_context(xc_handle, sid, ctx, ctx_len);
+
+ xc_interface_close(xc_handle);
+
+ if ( ret != 0 ) {
+ errno = -ret;
+ return PyErr_SetFromErrno(xc_error_obj);
+ }
+
+ return Py_BuildValue("s", ctx, ctx_len);
+}
+
+
+static PyMethodDef pyflask_methods[] = {
+ { "flask_context_to_sid",
+ (PyCFunction)pyflask_context_to_sid,
+ METH_KEYWORDS, "\n"
+ "Convert a context string to a dynamic SID.\n"
+ " context [str]: String specifying context to be converted\n"
+ "Returns: [int]: Numeric SID on success; -1 on error.\n" },
+
+ { "flask_sid_to_context",
+ (PyCFunction)pyflask_sid_to_context,
+ METH_KEYWORDS, "\n"
+ "Convert a dynamic SID to context string.\n"
+ " context [int]: SID to be converted\n"
+ "Returns: [str]: Numeric SID on success; -1 on error.\n" },
+
+ { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC initflask(void)
+{
+ Py_InitModule("flask", pyflask_methods);
+}
+
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/__init__.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/__init__.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,1 @@
+
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/acm/__init__.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/__init__.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,1 @@
+
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/acm/acm.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/acm/acm.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,668 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#============================================================================
+# Copyright (C) 2006 International Business Machines Corp.
+# Author: Reiner Sailer
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+import commands
+import logging
+import sys, os, string, re
+import traceback
+import shutil
+from xen.lowlevel import acm
+from xen.xend import sxp
+from xen.xend.XendLogging import log
+from xen.util import dictio
+
+#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)
+
+#other global variables
+NULL_SSIDREF = 0
+
+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.
+ """
+ sys.stderr.write("ACMError: " + msg + "\n")
+ raise ACMError(msg)
+
+
+
+active_policy = None
+
+
+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'])
+
+
+
+# Assumes a 'security' info [security access_control ...] [ssidref ...]
+def get_security_info(info, field):
+ """retrieves security field from self.info['security'])
+ allowed search fields: ssidref, label, policy
+ """
+ if isinstance(info, dict):
+ security = info['security']
+ elif isinstance(info, list):
+ security = sxp.child_value(info, 'security', )
+ if not security:
+ if field == 'ssidref':
+ #return default ssid
+ return 0
+ else:
+ err("Security information not found in info struct.")
+
+ if field == 'ssidref':
+ search = 'ssidref'
+ elif field in ['policy', 'label']:
+ search = 'access_control'
+ else:
+ err("Illegal field in get_security_info.")
+
+ for idx in range(0, len(security)):
+ if search != security[idx][0]:
+ continue
+ if search == 'ssidref':
+ return int(security[idx][1])
+ else:
+ for aidx in range(0, len(security[idx])):
+ if security[idx][aidx][0] == field:
+ return str(security[idx][aidx][1])
+
+ if search == 'ssidref':
+ return 0
+ else:
+ return None
+
+
+
+def get_security_printlabel(info):
+ """retrieves printable security label from self.info['security']),
+ preferably the label name and otherwise (if label is not specified
+ in config and cannot be found in mapping file) a hex string of the
+ ssidref or none if both not available
+ """
+ try:
+ if not on():
+ return "INACTIVE"
+ if active_policy in ["DEFAULT"]:
+ return "DEFAULT"
+
+ printlabel = get_security_info(info, 'label')
+ if printlabel:
+ return printlabel
+ ssidref = get_security_info(info, 'ssidref')
+ if not ssidref:
+ return None
+ #try to translate ssidref to a label
+ result = ssidref2label(ssidref)
+ if not result:
+ printlabel = "0x%08x" % ssidref
+ else:
+ printlabel = result
+ return printlabel
+ except ACMError:
+ #don't throw an exception in xm list
+ return "ERROR"
+
+
+
+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')") +
+ (primary, secondary, f, pol_exists) = getmapfile(None)
+ if not f:
+ if (pol_exists):
+ err("Mapping file for policy \'" + policyname + "\' 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()
+
+ #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, type):
+ """
+ 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 type == 'dom':
+ allowed_types.append('VM')
+ elif type == 'res':
+ allowed_types.append('RES')
+ else:
+ err("Invalid type. Must specify 'dom' or 'res'.")
+
+ (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 (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
+ pri_ssid.append(NULL_SSIDREF)
+ elif (type == '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]
+
+
+
+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 \'" + policyname + "\' in label does not match active policy \'"
+ + 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])
+ except:
+ err("Cannot determine decision.")
+
+ if decision:
+ return decision
+ else:
+ err("Cannot determine decision (Invalid parameter).")
+
+
+
+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 (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 (label, 'NULL')
+
+ (label, policy) = default_res_label()
+
+ # load the resource label file
+ res_label_cache = {}
+ try:
+ res_label_cache = dictio.dict_read("resources", res_label_filename)
+ except:
+ log.info("Resource label file not found.")
+ return default_res_label()
+
+ # find the resource information
+ if res_label_cache.has_key(resource):
+ (policy, label) = res_label_cache[resource]
+
+ return (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
+ (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 unify_resname(resource):
+ """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:
+ (type, resfile) = resource.split(":", 1)
+ except:
+ err("Resource spec '%s' contains no ':' delimiter" % resource)
+
+ if type == "tap":
+ try:
+ (subtype, resfile) = resfile.split(":")
+ except:
+ err("Resource spec '%s' contains no tap subtype" % resource)
+
+ if type in ["phy", "tap"]:
+ if not resfile.startswith("/"):
+ resfile = "/dev/" + resfile
+
+ #file: resources must specified with absolute path
+ if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
+ err("Invalid resource.")
+
+ # from here on absolute file names with resources
+ if type == "tap":
+ type = type + ":" + subtype
+ resource = type + ":" + 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
+
+ #build canonical resource name
+ resource = unify_resname(resource)
+
+ # if security is on, ask the hypervisor for a decision
+ if on():
+ (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:
+ (label, policy) = get_res_label(resource)
+ if policy != 'NULL':
+ raise ACMError("Security is off, but '"+resource+"' is labeled")
+ rtnval = 0
+
+ return rtnval
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/dummy/__init__.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/__init__.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,1 @@
+
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/dummy/dummy.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/dummy/dummy.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,4 @@
+active_policy = "";
+
+def on():
+ return 0
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/flask/__init__.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/__init__.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,1 @@
+
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/xsm/flask/flask.py
--- /dev/null Thu Jan 1 00:00:00 1970 +0000
+++ b/tools/python/xen/util/xsm/flask/flask.py Tue Dec 19 21:50:31 2006 -0500
@@ -0,0 +1,75 @@
+import sys
+from xen.lowlevel import flask
+from xen.xend import sxp
+
+active_policy = "";
+NULL_SSIDREF = 0;
+
+class ACMError(Exception):
+ def __init__(self,value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+def err(msg):
+ """Raise ACM exception.
+ """
+ sys.stderr.write("ACMError: " + msg + "\n")
+ raise ACMError(msg)
+
+def on():
+ return 1
+
+def get_security_info(info, field):
+ if isinstance(info, dict):
+ security = info['security']
+ elif isinstance(info, list):
+ security = sxp.child_value(info, 'security', )
+
+ for idx in range(0, len(security)):
+ if security[idx][0] != 'ssidref':
+ continue
+ if field == 'ssidref':
+ return int(security[idx][1])
+ elif field == 'label':
+ return flask.flask_sid_to_context(int(security[idx][1]))
+ else:
+ err("Field not found!")
+
+def get_security_printlabel(info):
+ return get_security_info(info, 'label')
+
+def ssidref2label(ssidref):
+ return flask.flask_sid_to_context(ssidref)
+
+def label2ssidref(label, policy, type):
+ return flask.flask_context_to_sid(label)
+
+def res_security_check(resource, domain_label):
+ return 1
+
+def get_res_security_details(resource):
+ return ("","","")
+
+def get_res_label(resource):
+ return ("","")
+
+def unify_resname(resource):
+ return ""
+
+def make_policy(policy_name):
+ return 1
+
+def load_policy(policy_name):
+ return 1
+
+def dump_policy():
+ print ""
+
+def list_labels(policy_name, condition):
+ labels = []
+ return labels
+
+def refresh_ssidref(config):
+ return config
+
diff -r 12923ba929c8 -r 0655af4eae49 tools/python/xen/util/security.py
--- a/tools/python/xen/util/security.py Sat Dec 16 11:54:25 2006 -0500
+++ /dev/null Thu Jan 1 00:00:00 1970 +0000
@@ -1,668 +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 <bdpayne@us.ibm.com>
-#============================================================================
-
-import commands
-import logging
-import sys, os, string, re
-import traceback
-import shutil
-from xen.lowlevel import acm
-from xen.xend import sxp
-from xen.xend.XendLogging import log
-from xen.util import dictio
-
-#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)
-
-#other global variables
-NULL_SSIDREF = 0
-
-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.
- """
- sys.stderr.write("ACMError: " + msg + "\n")
- raise ACMError(msg)
-
-
-
-active_policy = None
-
-
-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'])
-
-
-
-# Assumes a 'security' info [security access_control ...] [ssidref ...]
-def get_security_info(info, field):
- """retrieves security field from self.info['security'])
- allowed search fields: ssidref, label, policy
- """
- if isinstance(info, dict):
- security = info['security']
- elif isinstance(info, list):
- security = sxp.child_value(info, 'security', )
- if not security:
- if field == 'ssidref':
- #return default ssid
- return 0
- else:
- err("Security information not found in info struct.")
-
- if field == 'ssidref':
- search = 'ssidref'
- elif field in ['policy', 'label']:
- search = 'access_control'
- else:
- err("Illegal field in get_security_info.")
-
- for idx in range(0, len(security)):
- if search != security[idx][0]:
- continue
- if search == 'ssidref':
- return int(security[idx][1])
- else:
- for aidx in range(0, len(security[idx])):
- if security[idx][aidx][0] == field:
- return str(security[idx][aidx][1])
-
- if search == 'ssidref':
- return 0
- else:
- return None
-
-
-
-def get_security_printlabel(info):
- """retrieves printable security label from self.info['security']),
- preferably the label name and otherwise (if label is not specified
- in config and cannot be found in mapping file) a hex string of the
- ssidref or none if both not available
- """
- try:
- if not on():
- return "INACTIVE"
- if active_policy in ["DEFAULT"]:
- return "DEFAULT"
-
- printlabel = get_security_info(info, 'label')
- if printlabel:
- return printlabel
- ssidref = get_security_info(info, 'ssidref')
- if not ssidref:
- return None
- #try to translate ssidref to a label
- result = ssidref2label(ssidref)
- if not result:
- printlabel = "0x%08x" % ssidref
- else:
- printlabel = result
- return printlabel
- except ACMError:
- #don't throw an exception in xm list
- return "ERROR"
-
-
-
-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')")
-
- (primary, secondary, f, pol_exists) = getmapfile(None)
- if not f:
- if (pol_exists):
- err("Mapping file for policy \'" + policyname + "\' 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()
-
- #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, type):
- """
- 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 type == 'dom':
- allowed_types.append('VM')
- elif type == 'res':
- allowed_types.append('RES')
- else:
- err("Invalid type. Must specify 'dom' or 'res'.")
-
- (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 (type == 'res') and (primary == "CHWALL") and (len(pri_ssid) == 0):
- pri_ssid.append(NULL_SSIDREF)
- elif (type == '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]
-
-
-
-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 \'" + policyname + "\' in label does not match active policy \'"
- + 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])
- except:
- err("Cannot determine decision.")
-
- if decision:
- return decision
- else:
- err("Cannot determine decision (Invalid parameter).")
-
-
-
-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 (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 (label, 'NULL')
-
- (label, policy) = default_res_label()
-
- # load the resource label file
- res_label_cache = {}
- try:
- res_label_cache = dictio.dict_read("resources", res_label_filename)
- except:
- log.info("Resource label file not found.")
- return default_res_label()
-
- # find the resource information
- if res_label_cache.has_key(resource):
- (policy, label) = res_label_cache[resource]
-
- return (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
- (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 unify_resname(resource):
- """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:
- (type, resfile) = resource.split(":", 1)
- except:
- err("Resource spec '%s' contains no ':' delimiter" % resource)
-
- if type == "tap":
- try:
- (subtype, resfile) = resfile.split(":")
- except:
- err("Resource spec '%s' contains no tap subtype" % resource)
-
- if type in ["phy", "tap"]:
- if not resfile.startswith("/"):
- resfile = "/dev/" + resfile
-
- #file: resources must specified with absolute path
- if (not resfile.startswith("/")) or (not os.path.exists(resfile)):
- err("Invalid resource.")
-
- # from here on absolute file names with resources
- if type == "tap":
- type = type + ":" + subtype
- resource = type + ":" + 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
-
- #build canonical resource name
- resource = unify_resname(resource)
-
- # if security is on, ask the hypervisor for a decision
- if on():
- (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:
- (label, policy) = get_res_label(resource)
- if policy != 'NULL':
- raise ACMError("Security is off, but '"+resource+"' is labeled")
- rtnval = 0
-
- return rtnval
_______________________________________________
Xense-devel mailing list
Xense-devel@lists.xensource.com
http://lists.xensource.com/xense-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic