aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/man/xm.pod.193
-rw-r--r--tools/python/xen/util/security.py99
-rw-r--r--tools/python/xen/xend/server/blkif.py12
-rw-r--r--tools/python/xen/xm/addlabel.py149
-rw-r--r--tools/python/xen/xm/create.py59
-rw-r--r--tools/python/xen/xm/dry-run.py95
-rw-r--r--tools/python/xen/xm/getlabel.py134
-rw-r--r--tools/python/xen/xm/main.py28
-rw-r--r--tools/python/xen/xm/resources.py70
-rw-r--r--tools/python/xen/xm/rmlabel.py134
10 files changed, 832 insertions, 41 deletions
diff --git a/docs/man/xm.pod.1 b/docs/man/xm.pod.1
index b53c2a9b0a..1c8b9057cc 100644
--- a/docs/man/xm.pod.1
+++ b/docs/man/xm.pod.1
@@ -875,14 +875,43 @@ defined in the I<policy>. Unless specified, the default I<policy> is
the currently enforced access control policy. The default for I<type>
is 'dom'. The labels are arranged in alphabetical order.
-=item B<addlabel> I<configfile> I<label> [I<policy>]
+=item B<addlabel> I<label> dom I<configfile> [I<policy>]
+
+=item B<addlabel> I<label> res I<resource> [I<policy>]
Adds the security label with name I<label> to a domain
-I<configfile>. Unless specified, the default I<policy> is the
+I<configfile> (dom) or to the global resource label file for the
+given I<resource> (res). Unless specified, the default I<policy> is the
currently enforced access control policy. This subcommand also
verifies that the I<policy> definition supports the specified I<label>
name.
+=item B<rmlabel> dom I<configfile>
+
+=item B<rmlabel> res I<resource>
+
+Works the same as the I<addlabel> command (above), except that this
+command will remove the label from the domain I<configfile> (dom) or
+the global resource label file (res).
+
+=item B<getlabel> dom I<configfile>
+
+=item B<getlabel> res I<resource>
+
+Shows the label for the given I<configfile> or I<resource>
+
+=item B<resources>
+
+Lists all resources in the global resource label file. Each resource
+is listed with its associated label and policy name.
+
+=item B<dry-run> I<configfile>
+
+Determines if the specified I<configfile> describes a domain with a valid
+security configuration for type enforcement. The test shows the policy
+decision made for each resource label against the domain label as well as
+the overall decision.
+
B<CONFIGURING SECURITY>
=over 4
@@ -960,17 +989,18 @@ B<ATTACHING A SECURITY LABEL TO A DOMAIN>
=over 4
-This subcommand attaches a security label to a domain configuration
-file, here a HomeBanking label. The example policy ensures that this
-domain does not share information with other non-hombanking user
-domains (i.e., domains labeled as dom_Fun or dom_Boinc) and that it
-will not run simultaneously with domains labeled as dom_Fun.
+The I<addlabel> subcommand can attach a security label to a domain
+configuration file, here a HomeBanking label. The example policy
+ensures that this domain does not share information with other
+non-hombanking user domains (i.e., domains labeled as dom_Fun or
+dom_Boinc) and that it will not run simultaneously with domains
+labeled as dom_Fun.
We assume that the specified myconfig.xm configuration file actually
instantiates a domain that runs workloads related to home-banking,
probably just a browser environment for online-banking.
- xm addlabel myconfig.xm dom_HomeBanking
+ xm addlabel dom_HomeBanking dom myconfig.xm
The very simple configuration file might now look as printed
below. The I<addlabel> subcommand added the B<access_control> entry at
@@ -997,6 +1027,38 @@ permitted".
=back
+B<ATTACHING A SECURITY LABEL TO A RESOURCE>
+
+=over 4
+
+The I<addlabel> subcommand can also be used to attach a security
+label to a resource. Following the home banking example from above,
+we can label a disk resource (e.g., a physical partition or a file)
+to make it accessible to the home banking domain. The example policy
+provides a resource label, res_LogicalDiskPartition1(hda1), that is
+compatible with the HomeBanking domain label.
+
+ xm addlabel "res_LogicalDiskPartition1(hda1)" res phy:hda6
+
+After labeling this disk resource, it can be attached to the domain
+by adding a line to the domain configuration file. The line below
+attaches this disk to the domain at boot time.
+
+ disk = [ 'phy:hda6,sda2,w' ]
+
+Alternatively, the resource can be attached after booting the domain
+by using the I<block-attach> subcommand.
+
+ xm block-attach homebanking phy:hda6 sda2 w
+
+Note that labeled resources cannot be used when security is turned
+off. Any attempt to use labeled resources with security turned off
+will result in a failure with a corresponding error message. The
+solution is to enable security or, if security is no longer desired,
+to remove the resource label using the I<rmlabel> subcommand.
+
+=back
+
B<STARTING AND LISTING LABELED DOMAINS>
=over 4
@@ -1011,6 +1073,21 @@ B<STARTING AND LISTING LABELED DOMAINS>
=back
+B<LISTING LABELED RESOURCES>
+
+=over 4
+
+ xm resources
+
+ phy:hda6
+ policy: example.chwall_ste.client_v1
+ label: res_LogicalDiskPartition1(hda1)
+ file:/xen/disk_image/disk.img
+ policy: example.chwall_ste.client_v1
+ label: res_LogicalDiskPartition2(hda2)
+
+=back
+
B<POLICY REPRESENTATIONS>
=over 4
diff --git a/tools/python/xen/util/security.py b/tools/python/xen/util/security.py
index f778cbc1fe..9749d6b5c6 100644
--- a/tools/python/xen/util/security.py
+++ b/tools/python/xen/util/security.py
@@ -14,6 +14,7 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
import commands
@@ -21,11 +22,14 @@ import logging
import sys, os, string, re
import traceback
import shutil
+from xml.marshal import generic
from xen.lowlevel import acm
from xen.xend import sxp
+from xen.xend.XendLogging import log
#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"
xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
xensec_tool = "/usr/sbin/xensec_tool"
@@ -530,3 +534,98 @@ def list_labels(policy_name, condition):
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
+ configfile = res_label_filename
+ if not os.path.isfile(configfile):
+ log.info("Resource label file not found.")
+ return default_res_label()
+ fd = open(configfile, "rb")
+ res_label_cache = generic.load(fd)
+ fd.close()
+
+ # 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 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():
+ (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 --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py
index 02cd4f26f7..986d065be9 100644
--- a/tools/python/xen/xend/server/blkif.py
+++ b/tools/python/xen/xend/server/blkif.py
@@ -21,6 +21,7 @@ import re
import string
from xen.util import blkif
+from xen.util import security
from xen.xend import sxp
from xen.xend.XendError import VmError
@@ -40,15 +41,22 @@ class BlkifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
+ uname = sxp.child_value(config, 'uname')
dev = sxp.child_value(config, 'dev')
- (typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
+ (typ, params) = string.split(uname, ':', 1)
back = { 'dev' : dev,
'type' : typ,
'params' : params,
'mode' : sxp.child_value(config, 'mode', 'r')
- }
+ }
+
+ if security.on():
+ (label, ssidref, policy) = security.get_res_security_details(uname)
+ back.update({'acm_label' : label,
+ 'acm_ssidref': str(ssidref),
+ 'acm_policy' : policy})
if 'ioemu:' in dev:
(dummy, dev1) = string.split(dev, ':', 1)
diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py
index 57b0f79691..a688d10d0a 100644
--- a/tools/python/xen/xm/addlabel.py
+++ b/tools/python/xen/xm/addlabel.py
@@ -14,61 +14,156 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer <sailer@us.ibm.com>
+# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
-"""Labeling a domain configuration file.
+"""Labeling a domain configuration file or a resoruce.
"""
import sys, os
+import string
import traceback
+from xml.marshal import generic
+from xen.util import security
+def usage():
+ print "\nUsage: xm addlabel <label> dom <configfile> [<policy>]"
+ print " xm addlabel <label> res <resource> [<policy>]\n"
+ print " This program adds an acm_label entry into the 'configfile'"
+ print " for a domain or to the global resource label file for a"
+ print " resource. It derives the policy from the running hypervisor"
+ print " if it is not given (optional parameter). If a label already"
+ print " exists for the given domain or resource, then addlabel fails.\n"
+ security.err("Usage")
-from xen.util.security import ACMError, err, active_policy, label2ssidref, on, access_control_re
+def validate_config_file(configfile):
+ """Performs a simple sanity check on the configuration file passed on
+ the command line. We basically just want to make sure that it's
+ not a domain image file so we check for a few configuration values
+ and then we are satisfied. Returned 1 on success, otherwise 0.
+ """
+ # read in the config file
+ globs = {}
+ locs = {}
+ try:
+ execfile(configfile, globs, locs)
+ except:
+ print "Invalid configuration file."
+ return 0
+ # sanity check on the data from the file
+ count = 0
+ required = ['kernel', 'memory', 'name']
+ for (k, v) in locs.items():
+ if k in required:
+ count += 1
+ if count != 3:
+ print "Invalid configuration file."
+ return 0
+ else:
+ return 1
-def usage():
- print "\nUsage: xm addlabel <configfile> <label> [<policy>]\n"
- print " This program adds an acm_label entry into the 'configfile'."
- print " It derives the policy from the running hypervisor if it"
- print " is not given (optional parameter). If the configfile is"
- print " already labeled, then addlabel fails.\n"
- err("Usage")
-
-def main(argv):
+def add_resource_label(label, resource, policyref):
+ """Adds a resource label to the global resource label file.
+ """
try:
- policyref = None
- if len(argv) not in [3,4]:
- usage()
- configfile = argv[1]
- label = argv[2]
+ # sanity check: make sure this label can be instantiated later on
+ ssidref = security.label2ssidref(label, policyref, 'res')
- if len(argv) == 4:
- policyref = argv[3]
- elif on():
- policyref = active_policy
+ # sanity check on resource name
+ (type, file) = resource.split(":")
+ if type == "phy":
+ file = "/dev/" + file
+ if not os.path.exists(file):
+ print "Invalid resource '"+resource+"'"
+ return
+
+ # see if this resource is already in the file
+ file = security.res_label_filename
+ if not os.path.isfile(file):
+ print "Resource file not found, creating new file at:"
+ print "%s" % (file)
+ fd = open(file, "w")
+ fd.close();
+ access_control = {}
else:
- err("No active policy. Policy must be specified in command line.")
+ fd = open(file, "rb")
+ access_control = generic.load(fd)
+ fd.close()
+
+ if access_control.has_key(resource):
+ security.err("This resource is already labeled.")
- #sanity checks: make sure this label can be instantiated later on
- ssidref = label2ssidref(label, policyref, 'dom')
+ # write the data to file
+ new_entry = { resource : tuple([policyref, label]) }
+ access_control.update(new_entry)
+ fd = open(file, "wb")
+ generic.dump(access_control, fd)
+ fd.close()
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+def add_domain_label(label, configfile, policyref):
+ try:
+ # sanity checks: make sure this label can be instantiated later on
+ ssidref = security.label2ssidref(label, policyref, 'dom')
new_label = "access_control = ['policy=%s,label=%s']\n" % (policyref, label)
if not os.path.isfile(configfile):
- err("Configuration file \'" + configfile + "\' not found.")
+ security.err("Configuration file \'" + configfile + "\' not found.")
config_fd = open(configfile, "ra+")
for line in config_fd:
- if not access_control_re.match(line):
+ if not security.access_control_re.match(line):
continue
config_fd.close()
- err("Config file \'" + configfile + "\' is already labeled.")
+ security.err("Config file \'" + configfile + "\' is already labeled.")
config_fd.write(new_label)
config_fd.close()
- except ACMError:
+ except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
+def main (argv):
+ try:
+ policyref = None
+ if len(argv) not in [4,5]:
+ usage()
+ label = argv[1]
+
+ if len(argv) == 5:
+ policyref = argv[4]
+ elif security.on():
+ policyref = security.active_policy
+ else:
+ security.err("No active policy. Policy must be specified in command line.")
+
+ if argv[2].lower() == "dom":
+ configfile = argv[3]
+ if configfile[0] != '/':
+ for prefix in [".", "/etc/xen"]:
+ configfile = prefix + "/" + configfile
+ if os.path.isfile(configfile):
+ fd = open(configfile, "rb")
+ break
+ if not validate_config_file(configfile):
+ usage()
+ else:
+ add_domain_label(label, configfile, policyref)
+ elif argv[2].lower() == "res":
+ resource = argv[3]
+ add_resource_label(label, resource, policyref)
+ else:
+ usage()
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 3eadebb37d..432146a573 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -988,6 +988,56 @@ def parseCommandLine(argv):
return (gopts, config)
+def config_security_check(config, verbose):
+ """Checks each resource listed in the config to see if the active
+ policy will permit creation of a new domain using the config.
+ Returns 1 if the config passes all tests, otherwise 0.
+ """
+ answer = 1
+
+ # get the domain acm_label
+ domain_label = None
+ domain_policy = None
+ for x in sxp.children(config):
+ if sxp.name(x) == 'security':
+ domain_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
+ domain_policy = sxp.child_value(sxp.name(sxp.child0(x)), 'policy')
+
+ # if no domain label, use default
+ if not domain_label and security.on():
+ domain_label = security.ssidref2label(security.NULL_SSIDREF)
+ domain_policy = 'NULL'
+ elif not domain_label:
+ domain_label = ""
+ domain_policy = 'NULL'
+
+ if verbose:
+ print "Checking resources:"
+
+ # build a list of all resources in the config file
+ resources = []
+ for x in sxp.children(config):
+ if sxp.name(x) == 'device':
+ if sxp.name(sxp.child0(x)) == 'vbd':
+ resources.append(sxp.child_value(sxp.child0(x), 'uname'))
+
+ # perform a security check on each resource
+ for resource in resources:
+ try:
+ security.res_security_check(resource, domain_label)
+ if verbose:
+ print " %s: PERMITTED" % (resource)
+
+ except security.ACMError:
+ print " %s: DENIED" % (resource)
+ (res_label, res_policy) = security.get_res_label(resource)
+ print " --> res:"+res_label+" ("+res_policy+")"
+ print " --> dom:"+domain_label+" ("+domain_policy+")"
+ answer = 0
+
+ return answer
+
+
def main(argv):
try:
(opts, config) = parseCommandLine(argv)
@@ -1000,9 +1050,12 @@ def main(argv):
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
- dom = make_domain(opts, config)
- if opts.vals.console_autoconnect:
- console.execConsole(dom)
+ if not config_security_check(config, verbose=0):
+ err("Resource access violation")
+ else:
+ dom = make_domain(opts, config)
+ if opts.vals.console_autoconnect:
+ console.execConsole(dom)
if __name__ == '__main__':
main(sys.argv)
diff --git a/tools/python/xen/xm/dry-run.py b/tools/python/xen/xm/dry-run.py
new file mode 100644
index 0000000000..dbdad6747f
--- /dev/null
+++ b/tools/python/xen/xm/dry-run.py
@@ -0,0 +1,95 @@
+#============================================================================
+# 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: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Tests the security settings for a domain and its resources.
+"""
+from xen.util import security
+from xen.xm import create
+from xen.xend import sxp
+
+def usage():
+ print "\nUsage: xm dry-run <configfile>\n"
+ print "This program checks each resource listed in the configfile"
+ print "to see if the domain created by the configfile can access"
+ print "the resources. The status of each resource is listed"
+ print "individually along with the final security decision.\n"
+
+
+def check_domain_label(config):
+ """All that we need to check here is that the domain label exists and
+ is not null when security is on. Other error conditions are
+ handled when the config file is parsed.
+ """
+ answer = 0
+ secon = 0
+ default_label = security.ssidref2label(security.NULL_SSIDREF)
+ if security.on():
+ secon = 1
+
+ # get the domain acm_label
+ dom_label = None
+ dom_name = None
+ for x in sxp.children(config):
+ if sxp.name(x) == 'security':
+ dom_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
+ if sxp.name(x) == 'name':
+ dom_name = sxp.child0(x)
+
+ # sanity check on domain label
+ print "Checking domain:"
+ if (not secon) and (not dom_label):
+ print " %s: PERMITTED" % (dom_name)
+ answer = 1
+ elif (secon) and (dom_label) and (dom_label != default_label):
+ print " %s: PERMITTED" % (dom_name)
+ answer = 1
+ else:
+ print " %s: DENIED" % (dom_name)
+ if not secon:
+ print " --> Security off, but domain labeled"
+ else:
+ print " --> Domain not labeled"
+ answer = 0
+
+ return answer
+
+
+def main (argv):
+ if len(argv) != 2:
+ usage()
+ return
+
+ try:
+ passed = 0
+ (opts, config) = create.parseCommandLine(argv)
+ if check_domain_label(config):
+ if create.config_security_check(config, verbose=1):
+ passed = 1
+ else:
+ print "Checking resources: (skipped)"
+
+ if passed:
+ print "Dry Run: PASSED"
+ else:
+ print "Dry Run: FAILED"
+ except security.ACMError:
+ pass
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/tools/python/xen/xm/getlabel.py b/tools/python/xen/xm/getlabel.py
new file mode 100644
index 0000000000..33e2553b57
--- /dev/null
+++ b/tools/python/xen/xm/getlabel.py
@@ -0,0 +1,134 @@
+#============================================================================
+# 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: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Show the label for a domain or resoruce.
+"""
+import sys, os, re
+import string
+import traceback
+from xml.marshal import generic
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm getlabel dom <configfile>"
+ print " xm getlabel res <resource>\n"
+ print " This program shows the label for a domain or resource.\n"
+
+
+def get_resource_label(resource):
+ """Gets the resource label
+ """
+ try:
+ # read in the resource file
+ file = security.res_label_filename
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ access_control = generic.load(fd)
+ fd.close()
+ else:
+ print "Resource label file not found"
+ return
+
+ # get the entry and print label
+ if access_control.has_key(resource):
+ policy = access_control[resource][0]
+ label = access_control[resource][1]
+ print "policy="+policy+",label="+label
+ else:
+ print "Resource not labeled"
+ return
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+
+def get_domain_label(configfile):
+ try:
+ # open the domain config file
+ fd = None
+ file = None
+ if configfile[0] == '/':
+ fd = open(configfile, "rb")
+ else:
+ for prefix in [".", "/etc/xen"]:
+ file = prefix + "/" + configfile
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ break
+ if not fd:
+ print "Configuration file '"+configfile+"' not found."
+ return
+
+ # read in the domain config file, finding the label line
+ ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
+ ac_exit_re = re.compile(".*'\].*")
+ acline = ""
+ record = 0
+ for line in fd.readlines():
+ if ac_entry_re.match(line):
+ record = 1
+ if record:
+ acline = acline + line
+ if record and ac_exit_re.match(line):
+ record = 0
+ fd.close()
+
+ # send error message if we didn't find anything
+ if acline == "":
+ print "Label does not exist in domain configuration file."
+ return
+
+ # print out the label
+ (title, data) = acline.split("=", 1)
+ data = data.strip()
+ data = data.lstrip("[\'")
+ data = data.rstrip("\']")
+ (p, l) = data.split(",")
+ print data
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+
+def main (argv):
+ try:
+ if len(argv) != 3:
+ usage()
+ return
+
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ get_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ get_resource_label(resource)
+ else:
+ usage()
+
+ except security.ACMError:
+ traceback.print_exc(limit=1)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+
diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py
index a9be5e661c..6e58856e5a 100644
--- a/tools/python/xen/xm/main.py
+++ b/tools/python/xen/xm/main.py
@@ -30,6 +30,7 @@ import socket
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
import xmlrpclib
+import traceback
import xen.xend.XendProtocol
@@ -119,7 +120,11 @@ vnet_list_help = "vnet-list [-l|--long] list vnets"
vnet_create_help = "vnet-create <config> create a vnet from a config file"
vnet_delete_help = "vnet-delete <vnetid> delete a vnet"
vtpm_list_help = "vtpm-list <DomId> [--long] list virtual TPM devices"
-addlabel_help = "addlabel <ConfigFile> <label> Add security label to ConfigFile"
+addlabel_help = "addlabel <label> dom <configfile> Add security label to domain\n <label> res <resource> or resource"
+rmlabel_help = "rmlabel dom <configfile> Remove security label from domain\n res <resource> or resource"
+getlabel_help = "getlabel dom <configfile> Show security label for domain\n res <resource> or resource"
+dry_run_help = "dry-run <configfile> Tests if domain can access its resources"
+resources_help = "resources Show info for each labeled resource"
cfgbootpolicy_help = "cfgbootpolicy <policy> Add policy to boot configuration "
dumppolicy_help = "dumppolicy Print hypervisor ACM state information"
loadpolicy_help = "loadpolicy <policy> Load binary policy into hypervisor"
@@ -203,6 +208,10 @@ vnet_commands = [
acm_commands = [
"labels",
"addlabel",
+ "rmlabel",
+ "getlabel",
+ "dry-run",
+ "resources",
"makepolicy",
"loadpolicy",
"cfgbootpolicy",
@@ -992,6 +1001,19 @@ def xm_block_attach(args):
if len(args) == 5:
vbd.append(['backend', args[4]])
+ # verify that policy permits attaching this resource
+ try:
+ dominfo = server.xend.domain(dom)
+ domid = sxp.child_value(dominfo, 'domid')
+ (tmp1, label, tmp2, tmp3) = security.get_ssid(domid)
+ security.res_security_check(args[1], label)
+ except security.ACMError, e:
+ print e.value
+ sys.exit(1)
+ except:
+ traceback.print_exc(limit=1)
+ sys.exit(1)
+
server.xend.domain.device_create(dom, vbd)
@@ -1124,6 +1146,10 @@ subcommands = [
'shutdown',
'labels',
'addlabel',
+ 'rmlabel',
+ 'getlabel',
+ 'dry-run',
+ 'resources',
'cfgbootpolicy',
'makepolicy',
'loadpolicy',
diff --git a/tools/python/xen/xm/resources.py b/tools/python/xen/xm/resources.py
new file mode 100644
index 0000000000..6163a3b759
--- /dev/null
+++ b/tools/python/xen/xm/resources.py
@@ -0,0 +1,70 @@
+#============================================================================
+# 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: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""List the resource label information from the global resource label file
+"""
+import sys, os
+import string
+import traceback
+from xml.marshal import generic
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm resource\n"
+ print " This program lists information for each resource in the"
+ print " global resource label file\n"
+
+
+def print_resource_data(access_control):
+ """Prints out a resource dictionary to stdout
+ """
+ for resource in access_control:
+ (policy, label) = access_control[resource]
+ print resource
+ print " policy: "+policy
+ print " label: "+label
+
+
+def get_resource_data():
+ """Returns the resource dictionary.
+ """
+ file = security.res_label_filename
+ if not os.path.isfile(file):
+ security.err("Resource file not found.")
+
+ fd = open(file, "rb")
+ access_control = generic.load(fd)
+ fd.close()
+ return access_control
+
+
+def main (argv):
+ try:
+ access_control = get_resource_data()
+ print_resource_data(access_control)
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+
diff --git a/tools/python/xen/xm/rmlabel.py b/tools/python/xen/xm/rmlabel.py
new file mode 100644
index 0000000000..cac1104908
--- /dev/null
+++ b/tools/python/xen/xm/rmlabel.py
@@ -0,0 +1,134 @@
+#============================================================================
+# 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: Bryan D. Payne <bdpayne@us.ibm.com>
+#============================================================================
+
+"""Remove a label from a domain configuration file or a resoruce.
+"""
+import sys, os, re
+import string
+import traceback
+from xml.marshal import generic
+from xen.util import security
+
+def usage():
+ print "\nUsage: xm rmlabel dom <configfile>"
+ print " xm rmlabel res <resource>\n"
+ print " This program removes an acm_label entry from the 'configfile'"
+ print " for a domain or from the global resource label file for a"
+ print " resource. If the label does not exist for the given domain or"
+ print " resource, then rmlabel fails.\n"
+
+
+def rm_resource_label(resource):
+ """Removes a resource label from the global resource label file.
+ """
+ try:
+ # read in the resource file
+ file = security.res_label_filename
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ access_control = generic.load(fd)
+ fd.close()
+ else:
+ security.err("Resource file not found, cannot remove label!")
+
+ # remove the entry and update file
+ if access_control.has_key(resource):
+ del access_control[resource]
+ fd = open(file, "wb")
+ generic.dump(access_control, fd)
+ fd.close()
+ else:
+ security.err("Label does not exist in resource label file.")
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+
+def rm_domain_label(configfile):
+ try:
+ # open the domain config file
+ fd = None
+ file = None
+ if configfile[0] == '/':
+ fd = open(configfile, "rb")
+ else:
+ for prefix in [".", "/etc/xen"]:
+ file = prefix + "/" + configfile
+ if os.path.isfile(file):
+ fd = open(file, "rb")
+ break
+ if not fd:
+ security.err("Configuration file '"+configfile+"' not found.")
+
+ # read in the domain config file, removing label
+ ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
+ ac_exit_re = re.compile(".*'\].*")
+ file_contents = ""
+ comment = 0
+ removed = 0
+ for line in fd.readlines():
+ if ac_entry_re.match(line):
+ comment = 1
+ if comment:
+ removed = 1
+ line = "#"+line
+ if comment and ac_exit_re.match(line):
+ comment = 0
+ file_contents = file_contents + line
+ fd.close()
+
+ # send error message if we didn't find anything to remove
+ if not removed:
+ security.err("Label does not exist in domain configuration file.")
+
+ # write the data back out to the file
+ fd = open(file, "wb")
+ fd.writelines(file_contents)
+ fd.close()
+
+ except security.ACMError:
+ pass
+ except:
+ traceback.print_exc(limit=1)
+
+
+def main (argv):
+ try:
+ if len(argv) != 3:
+ usage()
+ return
+
+ if argv[1].lower() == "dom":
+ configfile = argv[2]
+ rm_domain_label(configfile)
+ elif argv[1].lower() == "res":
+ resource = argv[2]
+ rm_resource_label(resource)
+ else:
+ usage()
+
+ except security.ACMError:
+ traceback.print_exc(limit=1)
+
+
+if __name__ == '__main__':
+ main(sys.argv)
+
+