ia64/xen-unstable
changeset 9836:681a18bf049e
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@us.ibm.com>
and 'xend' and supports label/ssid translation support for
migration/life-migration/resume.
Signed-off by: Reiner Sailer <sailer@us.ibm.com>
author | smh22@firebug.cl.cam.ac.uk |
---|---|
date | Mon Apr 24 10:59:17 2006 +0100 (2006-04-24) |
parents | cf20dbbf5c2b |
children | c7b9b8a64755 |
files | tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xm/create.py tools/python/xen/xm/main.py |
line diff
1.1 --- a/tools/python/xen/xend/XendDomain.py Mon Apr 24 10:58:25 2006 +0100 1.2 +++ b/tools/python/xen/xend/XendDomain.py Mon Apr 24 10:59:17 2006 +0100 1.3 @@ -38,6 +38,7 @@ from xen.xend.XendError import XendError 1.4 from xen.xend.XendLogging import log 1.5 from xen.xend.xenstore.xstransact import xstransact 1.6 from xen.xend.xenstore.xswatch import xswatch 1.7 +from xen.util import security 1.8 1.9 1.10 xc = xen.lowlevel.xc.xc() 1.11 @@ -265,7 +266,7 @@ class XendDomain: 1.12 # handling in the relocation-socket handling code (relocate.py) is 1.13 # poor, so we need to log this for debugging. 1.14 log.exception("Restore failed") 1.15 - raise 1.16 + raise XendError("Restore failed") 1.17 1.18 1.19 def restore_(self, config): 1.20 @@ -283,6 +284,7 @@ class XendDomain: 1.21 """ 1.22 self.domains_lock.acquire() 1.23 try: 1.24 + security.refresh_ssidref(config) 1.25 dominfo = XendDomainInfo.restore(config) 1.26 self._add_domain(dominfo) 1.27 return dominfo
2.1 --- a/tools/python/xen/xend/XendDomainInfo.py Mon Apr 24 10:58:25 2006 +0100 2.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Mon Apr 24 10:59:17 2006 +0100 2.3 @@ -33,7 +33,7 @@ import threading 2.4 import xen.lowlevel.xc 2.5 from xen.util import asserts 2.6 from xen.util.blkif import blkdev_uname_to_file 2.7 - 2.8 +from xen.util import security 2.9 import balloon 2.10 import image 2.11 import sxp 2.12 @@ -126,7 +126,6 @@ VM_CONFIG_PARAMS = [ 2.13 # file, so those are handled separately. 2.14 ROUNDTRIPPING_CONFIG_ENTRIES = [ 2.15 ('uuid', str), 2.16 - ('ssidref', int), 2.17 ('vcpus', int), 2.18 ('vcpu_avail', int), 2.19 ('cpu_weight', float), 2.20 @@ -144,7 +143,6 @@ ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFI 2.21 # 2.22 VM_STORE_ENTRIES = [ 2.23 ('uuid', str), 2.24 - ('ssidref', int), 2.25 ('vcpus', int), 2.26 ('vcpu_avail', int), 2.27 ('memory', int), 2.28 @@ -297,6 +295,9 @@ def parseConfig(config): 2.29 result['cpu'] = get_cfg('cpu', int) 2.30 result['cpus'] = get_cfg('cpus', str) 2.31 result['image'] = get_cfg('image') 2.32 + tmp_security = get_cfg('security') 2.33 + if tmp_security: 2.34 + result['security'] = tmp_security 2.35 2.36 try: 2.37 if result['image']: 2.38 @@ -443,7 +444,7 @@ class XendDomainInfo: 2.39 self.validateInfo() 2.40 2.41 self.image = None 2.42 - 2.43 + self.security = None 2.44 self.store_port = None 2.45 self.store_mfn = None 2.46 self.console_port = None 2.47 @@ -521,6 +522,7 @@ class XendDomainInfo: 2.48 else: 2.49 entries = VM_STORE_ENTRIES 2.50 entries.append(('image', str)) 2.51 + entries.append(('security', str)) 2.52 2.53 map(lambda x, y: useIfNeeded(x[0], y), entries, 2.54 self.readVMDetails(entries)) 2.55 @@ -544,7 +546,6 @@ class XendDomainInfo: 2.56 2.57 try: 2.58 defaultInfo('name', lambda: "Domain-%d" % self.domid) 2.59 - defaultInfo('ssidref', lambda: 0) 2.60 defaultInfo('on_poweroff', lambda: "destroy") 2.61 defaultInfo('on_reboot', lambda: "restart") 2.62 defaultInfo('on_crash', lambda: "restart") 2.63 @@ -571,12 +572,16 @@ class XendDomainInfo: 2.64 defaultInfo('backend', lambda: []) 2.65 defaultInfo('device', lambda: []) 2.66 defaultInfo('image', lambda: None) 2.67 + defaultInfo('security', lambda: None) 2.68 2.69 self.check_name(self.info['name']) 2.70 2.71 if isinstance(self.info['image'], str): 2.72 self.info['image'] = sxp.from_string(self.info['image']) 2.73 2.74 + if isinstance(self.info['security'], str): 2.75 + self.info['security'] = sxp.from_string(self.info['security']) 2.76 + 2.77 if self.info['memory'] == 0: 2.78 if self.infoIsSet('mem_kb'): 2.79 self.info['memory'] = (self.info['mem_kb'] + 1023) / 1024 2.80 @@ -674,6 +679,20 @@ class XendDomainInfo: 2.81 if self.infoIsSet('image'): 2.82 to_store['image'] = sxp.to_string(self.info['image']) 2.83 2.84 + if self.infoIsSet('security'): 2.85 + security = self.info['security'] 2.86 + to_store['security'] = sxp.to_string(security) 2.87 + for idx in range(0, len(security)): 2.88 + if security[idx][0] == 'access_control': 2.89 + to_store['security/access_control'] = sxp.to_string([ security[idx][1] , security[idx][2] ]) 2.90 + for aidx in range(1, len(security[idx])): 2.91 + if security[idx][aidx][0] == 'label': 2.92 + to_store['security/access_control/label'] = security[idx][aidx][1] 2.93 + if security[idx][aidx][0] == 'policy': 2.94 + to_store['security/access_control/policy'] = security[idx][aidx][1] 2.95 + if security[idx][0] == 'ssidref': 2.96 + to_store['security/ssidref'] = str(security[idx][1]) 2.97 + 2.98 log.debug("Storing VM details: %s", to_store) 2.99 2.100 self.writeVm(to_store) 2.101 @@ -766,9 +785,8 @@ class XendDomainInfo: 2.102 self.storeVm('vcpu_avail', self.info['vcpu_avail']) 2.103 self.writeDom(self.vcpuDomDetails()) 2.104 2.105 - 2.106 - def getSsidref(self): 2.107 - return self.info['ssidref'] 2.108 + def getLabel(self): 2.109 + return security.get_security_info(self.info, 'label') 2.110 2.111 def getMemoryTarget(self): 2.112 """Get this domain's target memory size, in KB.""" 2.113 @@ -960,12 +978,21 @@ class XendDomainInfo: 2.114 """ 2.115 2.116 log.trace("XendDomainInfo.update(%s) on domain %d", info, self.domid) 2.117 - 2.118 if not info: 2.119 info = dom_get(self.domid) 2.120 if not info: 2.121 return 2.122 2.123 + #manually update ssidref / security fields 2.124 + if security.on() and info.has_key('ssidref'): 2.125 + if (info['ssidref'] != 0) and self.info.has_key('security'): 2.126 + security_field = self.info['security'] 2.127 + if not security_field: 2.128 + #create new security element 2.129 + self.info.update({'security': [['ssidref', str(info['ssidref'])]]}) 2.130 + #ssidref field not used any longer 2.131 + info.pop('ssidref') 2.132 + 2.133 self.info.update(info) 2.134 self.validateInfo() 2.135 self.refreshShutdown(info) 2.136 @@ -1002,7 +1029,6 @@ class XendDomainInfo: 2.137 s += " id=" + str(self.domid) 2.138 s += " name=" + self.info['name'] 2.139 s += " memory=" + str(self.info['memory']) 2.140 - s += " ssidref=" + str(self.info['ssidref']) 2.141 s += ">" 2.142 return s 2.143 2.144 @@ -1064,6 +1090,9 @@ class XendDomainInfo: 2.145 if self.infoIsSet('image'): 2.146 sxpr.append(['image', self.info['image']]) 2.147 2.148 + if self.infoIsSet('security'): 2.149 + sxpr.append(['security', self.info['security']]) 2.150 + 2.151 for cls in controllerClasses: 2.152 for config in self.getDeviceConfigurations(cls): 2.153 sxpr.append(['device', config]) 2.154 @@ -1165,12 +1194,11 @@ class XendDomainInfo: 2.155 @raise: VmError on error 2.156 """ 2.157 2.158 - log.debug('XendDomainInfo.construct: %s %s', 2.159 - self.domid, 2.160 - self.info['ssidref']) 2.161 + log.debug('XendDomainInfo.construct: %s', 2.162 + self.domid) 2.163 2.164 self.domid = xc.domain_create( 2.165 - dom = 0, ssidref = self.info['ssidref'], 2.166 + dom = 0, ssidref = security.get_security_info(self.info, 'ssidref'), 2.167 handle = uuid.fromString(self.info['uuid'])) 2.168 2.169 if self.domid < 0:
3.1 --- a/tools/python/xen/xm/create.py Mon Apr 24 10:58:25 2006 +0100 3.2 +++ b/tools/python/xen/xm/create.py Mon Apr 24 10:59:17 2006 +0100 3.3 @@ -35,6 +35,7 @@ import xen.xend.XendClient 3.4 from xen.xend.XendClient import server 3.5 from xen.xend.XendBootloader import bootloader 3.6 from xen.util import blkif 3.7 +from xen.util import security 3.8 3.9 from xen.xm.opts import * 3.10 3.11 @@ -145,10 +146,6 @@ gopts.var('memory', val='MEMORY', 3.12 fn=set_int, default=128, 3.13 use="Domain memory in MB.") 3.14 3.15 -gopts.var('ssidref', val='SSIDREF', 3.16 - fn=set_u32, default=0, 3.17 - use="Security Identifier.") 3.18 - 3.19 gopts.var('maxmem', val='MEMORY', 3.20 fn=set_int, default=None, 3.21 use="Maximum domain memory in MB.") 3.22 @@ -293,6 +290,14 @@ gopts.var('vtpm', val="instance=INSTANCE 3.23 number can be found in /etc/xen/vtpm.db. Use the backend in the 3.24 given domain.""") 3.25 3.26 +gopts.var('access_control', val="policy=POLICY,label=LABEL", 3.27 + fn=append_value, default=[], 3.28 + use="""Add a security label and the security policy reference that defines it. 3.29 + The local ssid reference is calculated when starting/resuming the domain. At 3.30 + this time, the policy is checked against the active policy as well. This way, 3.31 + migrating through save/restore is covered and local labels are automatically 3.32 + created correctly on the system where a domain is started / resumed.""") 3.33 + 3.34 gopts.var('nics', val="NUM", 3.35 fn=set_int, default=-1, 3.36 use="""DEPRECATED. Use empty vif entries instead. 3.37 @@ -502,6 +507,43 @@ def configure_usb(config_devs, vals): 3.38 config_usb = ['usb', ['path', path]] 3.39 config_devs.append(['device', config_usb]) 3.40 3.41 + 3.42 +def configure_security(config, vals): 3.43 + """Create the config for ACM security labels. 3.44 + """ 3.45 + access_control = vals.access_control 3.46 + num = len(access_control) 3.47 + if num == 1: 3.48 + d = access_control[0] 3.49 + policy = d.get('policy') 3.50 + label = d.get('label') 3.51 + if policy != security.active_policy: 3.52 + err("Security policy (" + policy + ") incompatible with enforced policy (" 3.53 + + security.active_policy + ")." ) 3.54 + config_access_control = ['access_control', 3.55 + ['policy', policy], 3.56 + ['label', label] ] 3.57 + 3.58 + #ssidref cannot be specified together with access_control 3.59 + if sxp.child_value(config, 'ssidref'): 3.60 + err("ERROR: SSIDREF and access_control are mutually exclusive but both specified!") 3.61 + #else calculate ssidre from label 3.62 + ssidref = security.label2ssidref(label, policy) 3.63 + if not ssidref : 3.64 + err("ERROR calculating ssidref from access_control.") 3.65 + security_label = ['security', [ config_access_control, ['ssidref' , ssidref ] ] ] 3.66 + config.append(security_label) 3.67 + elif num == 0: 3.68 + if hasattr(vals, 'ssidref'): 3.69 + if not security.on(): 3.70 + err("ERROR: Security ssidref specified but no policy active.") 3.71 + ssidref = getattr(vals, 'ssidref') 3.72 + security_label = ['security', [ [ 'ssidref' , int(ssidref) ] ] ] 3.73 + config.append(security_label) 3.74 + elif num > 1: 3.75 + err("VM config error: Multiple access_control definitions!") 3.76 + 3.77 + 3.78 def configure_vtpm(config_devs, vals): 3.79 """Create the config for virtual TPM interfaces. 3.80 """ 3.81 @@ -595,9 +637,9 @@ def make_config(vals): 3.82 if v: 3.83 config.append([n, v]) 3.84 3.85 - map(add_conf, ['name', 'memory', 'ssidref', 'maxmem', 'restart', 3.86 - 'on_poweroff', 'on_reboot', 'on_crash', 'vcpus']) 3.87 - 3.88 + map(add_conf, ['name', 'memory', 'maxmem', 'restart', 'on_poweroff', 3.89 + 'on_reboot', 'on_crash', 'vcpus']) 3.90 + 3.91 if vals.uuid is not None: 3.92 config.append(['uuid', vals.uuid]) 3.93 if vals.cpu is not None: 3.94 @@ -628,6 +670,7 @@ def make_config(vals): 3.95 configure_vifs(config_devs, vals) 3.96 configure_usb(config_devs, vals) 3.97 configure_vtpm(config_devs, vals) 3.98 + configure_security(config, vals) 3.99 config += config_devs 3.100 3.101 return config 3.102 @@ -696,6 +739,29 @@ def preprocess_vtpm(vals): 3.103 vtpms.append(d) 3.104 vals.vtpm = vtpms 3.105 3.106 +def preprocess_access_control(vals): 3.107 + if not vals.access_control: 3.108 + return 3.109 + access_controls = [] 3.110 + num = len(vals.access_control) 3.111 + if num == 1: 3.112 + access_control = (vals.access_control)[0] 3.113 + d = {} 3.114 + a = access_control.split(',') 3.115 + if len(a) > 2: 3.116 + err('Too many elements in access_control specifier: ' + access_control) 3.117 + for b in a: 3.118 + (k, v) = b.strip().split('=', 1) 3.119 + k = k.strip() 3.120 + v = v.strip() 3.121 + if k not in ['policy','label']: 3.122 + err('Invalid access_control specifier: ' + access_control) 3.123 + d[k] = v 3.124 + access_controls.append(d) 3.125 + vals.access_control = access_controls 3.126 + elif num > 1: 3.127 + err('Multiple access_control definitions.') 3.128 + 3.129 def preprocess_ip(vals): 3.130 if vals.ip or vals.dhcp != 'off': 3.131 dummy_nfs_server = '1.2.3.4' 3.132 @@ -785,6 +851,7 @@ def preprocess(vals): 3.133 preprocess_nfs(vals) 3.134 preprocess_vnc(vals) 3.135 preprocess_vtpm(vals) 3.136 + preprocess_access_control(vals) 3.137 3.138 3.139 def comma_sep_kv_to_dict(c):
4.1 --- a/tools/python/xen/xm/main.py Mon Apr 24 10:58:25 2006 +0100 4.2 +++ b/tools/python/xen/xm/main.py Mon Apr 24 10:59:17 2006 +0100 4.3 @@ -40,6 +40,7 @@ from xen.xm.opts import * 4.4 import console 4.5 import xen.xend.XendClient 4.6 from xen.xend.XendClient import server 4.7 +from xen.util import security 4.8 4.9 # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use 4.10 # getopt.getopt if gnu_getopt is not available. This will mean that options 4.11 @@ -55,6 +56,8 @@ create_help = """create [-c] <ConfigFil 4.12 destroy_help = "destroy <DomId> Terminate a domain immediately" 4.13 help_help = "help Display this message" 4.14 list_help = "list [--long] [DomId, ...] List information about domains" 4.15 +list_label_help = "list [--label] [DomId, ...] List information about domains including their labels" 4.16 + 4.17 mem_max_help = "mem-max <DomId> <Mem> Set maximum memory reservation for a domain" 4.18 mem_set_help = "mem-set <DomId> <Mem> Adjust the current memory usage for a domain" 4.19 migrate_help = "migrate <DomId> <Host> Migrate a domain to another machine" 4.20 @@ -114,6 +117,12 @@ vnet_list_help = "vnet-list [-l|--long] 4.21 vnet_create_help = "vnet-create <config> create a vnet from a config file" 4.22 vnet_delete_help = "vnet-delete <vnetid> delete a vnet" 4.23 vtpm_list_help = "vtpm-list <DomId> [--long] list virtual TPM devices" 4.24 +addlabel_help = "addlabel <ConfigFile> <label> Add security label to ConfigFile" 4.25 +cfgbootpolicy_help = "cfgbootpolicy <policy> Add policy to boot configuration " 4.26 +dumppolicy_help = "dumppolicy Print hypervisor ACM state information" 4.27 +loadpolicy_help = "loadpolicy <policy> Load binary policy into hypervisor" 4.28 +makepolicy_help = "makepolicy <policy> Build policy and create .bin/.map files" 4.29 +labels_help = "labels [policy] [type=DOM|..] List <type> labels for (active) policy." 4.30 4.31 short_command_list = [ 4.32 "console", 4.33 @@ -140,6 +149,7 @@ domain_commands = [ 4.34 "domid", 4.35 "domname", 4.36 "list", 4.37 + "list_label", 4.38 "mem-max", 4.39 "mem-set", 4.40 "migrate", 4.41 @@ -185,8 +195,17 @@ vnet_commands = [ 4.42 "vnet-delete", 4.43 ] 4.44 4.45 +acm_commands = [ 4.46 + "labels", 4.47 + "addlabel", 4.48 + "makepolicy", 4.49 + "loadpolicy", 4.50 + "cfgbootpolicy", 4.51 + "dumppolicy" 4.52 + ] 4.53 + 4.54 all_commands = (domain_commands + host_commands + scheduler_commands + 4.55 - device_commands + vnet_commands) 4.56 + device_commands + vnet_commands + acm_commands) 4.57 4.58 4.59 def commandToHelp(cmd): 4.60 @@ -225,6 +244,9 @@ xm full list of subcommands: 4.61 Vnet commands: 4.62 """ + help_spacer.join(map(commandToHelp, vnet_commands)) + """ 4.63 4.64 + Access Control commands: 4.65 + """ + help_spacer.join(map(commandToHelp, acm_commands)) + """ 4.66 + 4.67 <DomName> can be substituted for <DomId> in xm subcommands. 4.68 4.69 For a short list of subcommands run 'xm help' 4.70 @@ -332,8 +354,9 @@ def getDomains(domain_names): 4.71 def xm_list(args): 4.72 use_long = 0 4.73 show_vcpus = 0 4.74 + show_labels = 0 4.75 try: 4.76 - (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus']) 4.77 + (options, params) = getopt.gnu_getopt(args, 'lv', ['long','vcpus','label']) 4.78 except getopt.GetoptError, opterr: 4.79 err(opterr) 4.80 sys.exit(1) 4.81 @@ -343,6 +366,8 @@ def xm_list(args): 4.82 use_long = 1 4.83 if k in ['-v', '--vcpus']: 4.84 show_vcpus = 1 4.85 + if k in ['--label']: 4.86 + show_labels = 1 4.87 4.88 if show_vcpus: 4.89 print >>sys.stderr, ( 4.90 @@ -354,6 +379,8 @@ def xm_list(args): 4.91 4.92 if use_long: 4.93 map(PrettyPrint.prettyprint, doms) 4.94 + elif show_labels: 4.95 + xm_label_list(doms) 4.96 else: 4.97 xm_brief_list(doms) 4.98 4.99 @@ -369,7 +396,7 @@ def parse_doms_info(info): 4.100 'vcpus' : get_info('online_vcpus', int, 0), 4.101 'state' : get_info('state', str, '??'), 4.102 'cpu_time' : get_info('cpu_time', float, 0), 4.103 - 'ssidref' : get_info('ssidref', int, 0), 4.104 + 'seclabel' : security.get_security_printlabel(info), 4.105 } 4.106 4.107 4.108 @@ -391,13 +418,29 @@ def xm_brief_list(doms): 4.109 print 'Name ID Mem(MiB) VCPUs State Time(s)' 4.110 for dom in doms: 4.111 d = parse_doms_info(dom) 4.112 - if (d['ssidref'] != 0): 4.113 - d['ssidstr'] = (" s:%04x/p:%04x" % 4.114 - ((d['ssidref'] >> 16) & 0xffff, 4.115 - d['ssidref'] & 0xffff)) 4.116 + print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f" % d) 4.117 + 4.118 + 4.119 +def xm_label_list(doms): 4.120 + output = [] 4.121 + print 'Name ID Mem(MiB) VCPUs State Time(s) Label' 4.122 + for dom in doms: 4.123 + d = parse_doms_info(dom) 4.124 + l = "%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f " % d 4.125 + if security.active_policy not in ['INACTIVE', 'NULL', 'DEFAULT']: 4.126 + if d['seclabel']: 4.127 + line = (l, d['seclabel']) 4.128 + else: 4.129 + line = (l, "ERROR") 4.130 + elif security.active_policy in ['DEFAULT']: 4.131 + line = (l, "DEFAULT") 4.132 else: 4.133 - d['ssidstr'] = "" 4.134 - print ("%(name)-32s %(dom)3d %(mem)8d %(vcpus)5d %(state)5s %(cpu_time)7.1f%(ssidstr)s" % d) 4.135 + line = (l, "INACTIVE") 4.136 + output.append(line) 4.137 + #sort by labels 4.138 + output.sort(lambda x,y: cmp( x[1].lower(), y[1].lower())) 4.139 + for l in output: 4.140 + print l[0] + l[1] 4.141 4.142 4.143 def xm_vcpu_list(args): 4.144 @@ -1010,7 +1053,13 @@ subcommands = [ 4.145 'create', 4.146 'migrate', 4.147 'sysrq', 4.148 - 'shutdown' 4.149 + 'shutdown', 4.150 + 'labels', 4.151 + 'addlabel', 4.152 + 'cfgbootpolicy', 4.153 + 'makepolicy', 4.154 + 'loadpolicy', 4.155 + 'dumppolicy' 4.156 ] 4.157 4.158 for c in subcommands: