[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |