[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [Patch 7 / 8][XM] - Xen Management integration



This patch integrates the new access control management tools into 'xm' and 'xend' and supports label/ssid translation support for migration/life-migration/resume.

Signed-off by: Reiner Sailer <sailer@xxxxxxxxxx>

---
 tools/python/xen/xend/XendDomain.py     |    4 +
 tools/python/xen/xend/XendDomainInfo.py |   56 ++++++++++++++++------
 tools/python/xen/xm/create.py           |   81 +++++++++++++++++++++++++++++---
 tools/python/xen/xm/main.py             |   69 +++++++++++++++++++++++----
 4 files changed, 178 insertions(+), 32 deletions(-)

Index: xen-unstable.hg-shype/tools/python/xen/xend/XendDomain.py
===================================================================
--- xen-unstable.hg-shype.orig/tools/python/xen/xend/XendDomain.py
+++ xen-unstable.hg-shype/tools/python/xen/xend/XendDomain.py
@@ -38,6 +38,7 @@ from xen.xend.XendError import XendError
 from xen.xend.XendLogging import log
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.xenstore.xswatch import xswatch
+from xen.util import security
 
 
 xc = xen.lowlevel.xc.xc()
@@ -265,7 +266,7 @@ class XendDomain:
             # handling in the relocation-socket handling code (relocate.py) is
             # poor, so we need to log this for debugging.
             log.exception("Restore failed")
-            raise
+            raise XendError("Restore failed")
 
 
     def restore_(self, config):
@@ -283,6 +284,7 @@ class XendDomain:
         """
         self.domains_lock.acquire()
         try:
+            security.refresh_ssidref(config)
             dominfo = XendDomainInfo.restore(config)
             self._add_domain(dominfo)
             return dominfo
Index: xen-unstable.hg-shype/tools/python/xen/xend/XendDomainInfo.py
===================================================================
--- xen-unstable.hg-shype.orig/tools/python/xen/xend/XendDomainInfo.py
+++ xen-unstable.hg-shype/tools/python/xen/xend/XendDomainInfo.py
@@ -33,7 +33,7 @@ import threading
 import xen.lowlevel.xc
 from xen.util import asserts
 from xen.util.blkif import blkdev_uname_to_file
-
+from xen.util import security
 import balloon
 import image
 import sxp
@@ -120,7 +120,6 @@ VM_CONFIG_PARAMS = [
 # file, so those are handled separately.
 ROUNDTRIPPING_CONFIG_ENTRIES = [
     ('uuid',       str),
-    ('ssidref',    int),
     ('vcpus',      int),
     ('vcpu_avail', int),
     ('cpu_weight', float),
@@ -138,7 +137,6 @@ ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFI
 #
 VM_STORE_ENTRIES = [
     ('uuid',       str),
-    ('ssidref',    int),
     ('vcpus',      int),
     ('vcpu_avail', int),
     ('memory',     int),
@@ -291,6 +289,9 @@ def parseConfig(config):
     result['cpu']   = get_cfg('cpu',  int)
     result['cpus']  = get_cfg('cpus', str)
     result['image'] = get_cfg('image')
+    tmp_security = get_cfg('security')
+    if tmp_security:
+        result['security'] = tmp_security
 
     try:
         if result['image']:
@@ -437,7 +438,7 @@ class XendDomainInfo:
         self.validateInfo()
 
         self.image = None
-
+        self.security = None
         self.store_port = None
         self.store_mfn = None
         self.console_port = None
@@ -515,6 +516,7 @@ class XendDomainInfo:
         else:
             entries = VM_STORE_ENTRIES
         entries.append(('image', str))
+        entries.append(('security', str))
 
         map(lambda x, y: useIfNeeded(x[0], y), entries,
             self.readVMDetails(entries))
@@ -538,7 +540,6 @@ class XendDomainInfo:
 
         try:
             defaultInfo('name',         lambda: "Domain-%d" % self.domid)
-            defaultInfo('ssidref',      lambda: 0)
             defaultInfo('on_poweroff',  lambda: "destroy")
             defaultInfo('on_reboot',    lambda: "restart")
             defaultInfo('on_crash',     lambda: "restart")
@@ -565,12 +566,16 @@ class XendDomainInfo:
             defaultInfo('backend',      lambda: [])
             defaultInfo('device',       lambda: [])
             defaultInfo('image',        lambda: None)
+            defaultInfo('security',     lambda: None)
 
             self.check_name(self.info['name'])
 
             if isinstance(self.info['image'], str):
                 self.info['image'] = sxp.from_string(self.info['image'])
 
+            if isinstance(self.info['security'], str):
+                self.info['security'] = sxp.from_string(self.info['security'])
+
             if self.info['memory'] == 0:
                 if self.infoIsSet('mem_kb'):
                     self.info['memory'] = (self.info['mem_kb'] + 1023) / 1024
@@ -668,6 +673,20 @@ class XendDomainInfo:
         if self.infoIsSet('image'):
             to_store['image'] = sxp.to_string(self.info['image'])
 
+        if self.infoIsSet('security'):
+            security = self.info['security']
+            to_store['security'] = sxp.to_string(security)
+            for idx in range(0, len(security)):
+                if security[idx][0] == 'access_control':
+                    to_store['security/access_control'] = sxp.to_string([ 
security[idx][1] , security[idx][2] ])
+                    for aidx in range(1, len(security[idx])):
+                        if security[idx][aidx][0] == 'label':
+                            to_store['security/access_control/label'] = 
security[idx][aidx][1]
+                        if security[idx][aidx][0] == 'policy':
+                            to_store['security/access_control/policy'] = 
security[idx][aidx][1]
+                if security[idx][0] == 'ssidref':
+                    to_store['security/ssidref'] = str(security[idx][1])
+
         log.debug("Storing VM details: %s", to_store)
 
         self.writeVm(to_store)
@@ -760,9 +779,8 @@ class XendDomainInfo:
         self.storeVm('vcpu_avail', self.info['vcpu_avail'])
         self.writeDom(self.vcpuDomDetails())
 
-
-    def getSsidref(self):
-        return self.info['ssidref']
+    def getLabel(self):
+        return security.get_security_info(self.info, 'label')
 
     def getMemoryTarget(self):
         """Get this domain's target memory size, in KB."""
@@ -954,12 +972,21 @@ class XendDomainInfo:
         """
 
         log.trace("XendDomainInfo.update(%s) on domain %d", info, self.domid)
-
         if not info:
             info = dom_get(self.domid)
             if not info:
                 return
             
+        #manually update ssidref / security fields
+        if security.on() and info.has_key('ssidref'):
+            if (info['ssidref'] != 0) and self.info.has_key('security'):
+                security_field = self.info['security']
+                if not security_field:
+                    #create new security element
+                    self.info.update({'security': [['ssidref', 
str(info['ssidref'])]]})
+            #ssidref field not used any longer
+        info.pop('ssidref')
+
         self.info.update(info)
         self.validateInfo()
         self.refreshShutdown(info)
@@ -996,7 +1023,6 @@ class XendDomainInfo:
         s += " id=" + str(self.domid)
         s += " name=" + self.info['name']
         s += " memory=" + str(self.info['memory'])
-        s += " ssidref=" + str(self.info['ssidref'])
         s += ">"
         return s
 
@@ -1058,6 +1084,9 @@ class XendDomainInfo:
         if self.infoIsSet('image'):
             sxpr.append(['image', self.info['image']])
 
+        if self.infoIsSet('security'):
+            sxpr.append(['security', self.info['security']])
+
         for cls in controllerClasses:
             for config in self.getDeviceConfigurations(cls):
                 sxpr.append(['device', config])
@@ -1159,12 +1188,11 @@ class XendDomainInfo:
         @raise: VmError on error
         """
 
-        log.debug('XendDomainInfo.construct: %s %s',
-                  self.domid,
-                  self.info['ssidref'])
+        log.debug('XendDomainInfo.construct: %s',
+                  self.domid)
 
         self.domid = xc.domain_create(
-            dom = 0, ssidref = self.info['ssidref'],
+            dom = 0, ssidref = security.get_security_info(self.info, 
'ssidref'),
             handle = uuid.fromString(self.info['uuid']))
 
         if self.domid < 0:
Index: xen-unstable.hg-shype/tools/python/xen/xm/create.py
===================================================================
--- xen-unstable.hg-shype.orig/tools/python/xen/xm/create.py
+++ xen-unstable.hg-shype/tools/python/xen/xm/create.py
@@ -35,6 +35,7 @@ import xen.xend.XendClient
 from xen.xend.XendClient import server
 from xen.xend.XendBootloader import bootloader
 from xen.util import blkif
+from xen.util import security
 
 from xen.xm.opts import *
 
@@ -145,10 +146,6 @@ gopts.var('memory', val='MEMORY',
           fn=set_int, default=128,
           use="Domain memory in MB.")
 
-gopts.var('ssidref', val='SSIDREF',
-          fn=set_u32, default=0, 
-          use="Security Identifier.")
-
 gopts.var('maxmem', val='MEMORY',
           fn=set_int, default=None,
           use="Maximum domain memory in MB.")
@@ -293,6 +290,14 @@ gopts.var('vtpm', val="instance=INSTANCE
           number can be found in /etc/xen/vtpm.db. Use the backend in the
           given domain.""")
 
+gopts.var('access_control', val="policy=POLICY,label=LABEL",
+          fn=append_value, default=[],
+          use="""Add a security label and the security policy reference that 
defines it.
+          The local ssid reference is calculated when starting/resuming the 
domain. At
+          this time, the policy is checked against the active policy as well. 
This way,
+          migrating through save/restore is covered and local labels are 
automatically
+          created correctly on the system where a domain is started / 
resumed.""")
+
 gopts.var('nics', val="NUM",
           fn=set_int, default=-1,
           use="""DEPRECATED.  Use empty vif entries instead.
@@ -502,6 +507,43 @@ def configure_usb(config_devs, vals):
         config_usb = ['usb', ['path', path]]
         config_devs.append(['device', config_usb])
 
+
+def configure_security(config, vals):
+    """Create the config for ACM security labels.
+    """
+    access_control = vals.access_control
+    num = len(access_control)
+    if num == 1:
+        d = access_control[0]
+        policy = d.get('policy')
+        label = d.get('label')
+        if policy != security.active_policy:
+            err("Security policy (" + policy + ") incompatible with enforced 
policy ("
+                + security.active_policy + ")." )
+        config_access_control = ['access_control',
+                                 ['policy', policy],
+                                 ['label', label] ]
+
+        #ssidref cannot be specified together with access_control
+        if sxp.child_value(config, 'ssidref'):
+            err("ERROR: SSIDREF and access_control are mutually exclusive but 
both specified!")
+        #else calculate ssidre from label
+        ssidref = security.label2ssidref(label, policy)
+        if not ssidref :
+            err("ERROR calculating ssidref from access_control.")
+        security_label = ['security', [ config_access_control, ['ssidref' , 
ssidref ] ] ]
+        config.append(security_label)
+    elif num == 0:
+        if hasattr(vals, 'ssidref'):
+            if not security.on():
+                err("ERROR: Security ssidref specified but no policy active.")
+            ssidref = getattr(vals, 'ssidref')
+            security_label = ['security', [ [ 'ssidref' , int(ssidref) ] ] ]
+            config.append(security_label)
+    elif num > 1:
+        err("VM config error: Multiple access_control definitions!")
+
+
 def configure_vtpm(config_devs, vals):
     """Create the config for virtual TPM interfaces.
     """
@@ -595,9 +637,9 @@ def make_config(vals):
             if v:
                 config.append([n, v])
 
-    map(add_conf, ['name', 'memory', 'ssidref', 'maxmem', 'restart',
-                   'on_poweroff', 'on_reboot', 'on_crash', 'vcpus'])
-    
+    map(add_conf, ['name', 'memory', 'maxmem', 'restart', 'on_poweroff',
+                   'on_reboot', 'on_crash', 'vcpus'])
+
     if vals.uuid is not None:
         config.append(['uuid', vals.uuid])
     if vals.cpu is not None:
@@ -628,6 +670,7 @@ def make_config(vals):
     configure_vifs(config_devs, vals)
     configure_usb(config_devs, vals)
     configure_vtpm(config_devs, vals)
+    configure_security(config, vals)
     config += config_devs
 
     return config
@@ -696,6 +739,29 @@ def preprocess_vtpm(vals):
         vtpms.append(d)
     vals.vtpm = vtpms
 
+def preprocess_access_control(vals):
+    if not vals.access_control:
+        return
+    access_controls = []
+    num = len(vals.access_control)
+    if num == 1:
+        access_control = (vals.access_control)[0]
+        d = {}
+        a = access_control.split(',')
+        if len(a) > 2:
+            err('Too many elements in access_control specifier: ' + 
access_control)
+        for b in a:
+            (k, v) = b.strip().split('=', 1)
+            k = k.strip()
+            v = v.strip()
+            if k not in ['policy','label']:
+                err('Invalid access_control specifier: ' + access_control)
+            d[k] = v
+        access_controls.append(d)
+        vals.access_control = access_controls
+    elif num > 1:
+        err('Multiple access_control definitions.')
+
 def preprocess_ip(vals):
     if vals.ip or vals.dhcp != 'off':
         dummy_nfs_server = '1.2.3.4'
@@ -785,6 +851,7 @@ def preprocess(vals):
     preprocess_nfs(vals)
     preprocess_vnc(vals)
     preprocess_vtpm(vals)
+    preprocess_access_control(vals)
 
 
 def comma_sep_kv_to_dict(c):
Index: xen-unstable.hg-shype/tools/python/xen/xm/main.py
===================================================================
--- xen-unstable.hg-shype.orig/tools/python/xen/xm/main.py
+++ xen-unstable.hg-shype/tools/python/xen/xm/main.py
@@ -40,6 +40,7 @@ from xen.xm.opts import *
 import console
 import xen.xend.XendClient
 from xen.xend.XendClient import server
+from xen.util import security
 
 # getopt.gnu_getopt is better, but only exists in Python 2.3+.  Use
 # getopt.getopt if gnu_getopt is not available.  This will mean that options
@@ -55,6 +56,8 @@ create_help =  """create [-c] <ConfigFil
 destroy_help = "destroy <DomId>                  Terminate a domain 
immediately"
 help_help =    "help                             Display this message"
 list_help =    "list [--long] [DomId, ...]       List information about 
domains"
+list_label_help = "list [--label] [DomId, ...]      List information about 
domains including their labels"
+
 mem_max_help = "mem-max <DomId> <Mem>            Set maximum memory 
reservation for a domain"
 mem_set_help = "mem-set <DomId> <Mem>            Adjust the current memory 
usage for a domain"
 migrate_help = "migrate <DomId> <Host>           Migrate a domain to another 
machine"
@@ -114,6 +117,12 @@ vnet_list_help = "vnet-list [-l|--long] 
 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"
+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"
+makepolicy_help = "makepolicy <policy>              Build policy and create 
.bin/.map files"
+labels_help     = "labels [policy] [type=DOM|..]    List <type> labels for 
(active) policy."
 
 short_command_list = [
     "console",
@@ -140,6 +149,7 @@ domain_commands = [
     "domid",
     "domname",
     "list",
+    "list_label",
     "mem-max",
     "mem-set",
     "migrate",
@@ -185,8 +195,17 @@ vnet_commands = [
     "vnet-delete",
     ]
 
+acm_commands = [
+    "labels",
+    "addlabel",
+    "makepolicy",
+    "loadpolicy",
+    "cfgbootpolicy",
+    "dumppolicy"
+    ]
+
 all_commands = (domain_commands + host_commands + scheduler_commands +
-                device_commands + vnet_commands)
+                device_commands + vnet_commands + acm_commands)
 
 
 def commandToHelp(cmd):
@@ -225,6 +244,9 @@ xm full list of subcommands:
   Vnet commands:
    """ + help_spacer.join(map(commandToHelp,  vnet_commands)) + """
 
+  Access Control commands:
+   """ + help_spacer.join(map(commandToHelp,  acm_commands)) + """
+
 <DomName> can be substituted for <DomId> in xm subcommands.
 
 For a short list of subcommands run 'xm help'
@@ -332,8 +354,9 @@ def getDomains(domain_names):
 def xm_list(args):
     use_long = 0
     show_vcpus = 0
+    show_labels = 0
     try:
-        (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus'])
+        (options, params) = getopt.gnu_getopt(args, 'lv', 
['long','vcpus','label'])
     except getopt.GetoptError, opterr:
         err(opterr)
         sys.exit(1)
@@ -343,6 +366,8 @@ def xm_list(args):
             use_long = 1
         if k in ['-v', '--vcpus']:
             show_vcpus = 1
+        if k in ['--label']:
+            show_labels = 1
 
     if show_vcpus:
         print >>sys.stderr, (
@@ -354,6 +379,8 @@ def xm_list(args):
 
     if use_long:
         map(PrettyPrint.prettyprint, doms)
+    elif show_labels:
+        xm_label_list(doms)
     else:
         xm_brief_list(doms)
 
@@ -369,7 +396,7 @@ def parse_doms_info(info):
         'vcpus'    : get_info('online_vcpus', int,   0),
         'state'    : get_info('state',        str,   '??'),
         'cpu_time' : get_info('cpu_time',     float, 0),
-        'ssidref'  : get_info('ssidref',      int,   0),
+        'seclabel' : security.get_security_printlabel(info),
         }
 
 
@@ -391,13 +418,29 @@ def xm_brief_list(doms):
     print 'Name                              ID Mem(MiB) VCPUs State  Time(s)'
     for dom in doms:
         d = parse_doms_info(dom)
-        if (d['ssidref'] != 0):
-            d['ssidstr'] = (" s:%04x/p:%04x" % 
-                            ((d['ssidref'] >> 16) & 0xffff,
-                              d['ssidref']        & 0xffff))
+        print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s 
%(cpu_time)7.1f" % d)
+
+
+def xm_label_list(doms):
+    output = []
+    print 'Name                              ID Mem(MiB) VCPUs State  Time(s)  
Label'
+    for dom in doms:
+        d = parse_doms_info(dom)
+        l = "%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s 
%(cpu_time)7.1f  " % d
+        if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']:
+            if d['seclabel']:
+                line = (l, d['seclabel'])
+            else:
+                line = (l, "ERROR")
+        elif security.active_policy in ['DEFAULT']:
+            line = (l, "DEFAULT")
         else:
-            d['ssidstr'] = ""
-        print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s 
%(cpu_time)7.1f%(ssidstr)s" % d)
+            line = (l, "INACTIVE")
+        output.append(line)
+    #sort by labels
+    output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower()))
+    for l in output:
+        print l[0] + l[1]
 
 
 def xm_vcpu_list(args):
@@ -1010,7 +1053,13 @@ subcommands = [
     'create',
     'migrate',
     'sysrq',
-    'shutdown'
+    'shutdown',
+    'labels',
+    'addlabel',
+    'cfgbootpolicy',
+    'makepolicy',
+    'loadpolicy',
+    'dumppolicy'
     ]
 
 for c in subcommands:



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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.