diff options
-rw-r--r-- | tools/libxen/include/xen/api/xen_vif.h | 14 | ||||
-rw-r--r-- | tools/libxen/src/xen_vif.c | 39 | ||||
-rw-r--r-- | tools/python/xen/util/security.py | 48 | ||||
-rw-r--r-- | tools/python/xen/xend/XendAPI.py | 19 | ||||
-rw-r--r-- | tools/python/xen/xend/XendConfig.py | 10 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomain.py | 23 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomainInfo.py | 2 | ||||
-rw-r--r-- | tools/python/xen/xend/XendXSPolicyAdmin.py | 12 | ||||
-rw-r--r-- | tools/python/xen/xend/server/netif.py | 43 | ||||
-rw-r--r-- | tools/python/xen/xm/addlabel.py | 41 | ||||
-rw-r--r-- | tools/python/xen/xm/create.dtd | 3 | ||||
-rw-r--r-- | tools/python/xen/xm/create.py | 3 | ||||
-rw-r--r-- | tools/python/xen/xm/getlabel.py | 26 | ||||
-rw-r--r-- | tools/python/xen/xm/rmlabel.py | 38 | ||||
-rw-r--r-- | tools/python/xen/xm/xenapi_create.py | 13 |
15 files changed, 312 insertions, 22 deletions
diff --git a/tools/libxen/include/xen/api/xen_vif.h b/tools/libxen/include/xen/api/xen_vif.h index 26608f0af9..3fb8d7128e 100644 --- a/tools/libxen/include/xen/api/xen_vif.h +++ b/tools/libxen/include/xen/api/xen_vif.h @@ -362,4 +362,18 @@ extern bool xen_vif_get_all(xen_session *session, struct xen_vif_set **result); +/** + * Set the security label of a VIF. + */ +extern bool +xen_vif_set_security_label(xen_session *session, int64_t *result, xen_vif vif, + char *label, char *oldlabel); + + +/** + * Get the security label of a VIF. + */ +extern bool +xen_vif_get_security_label(xen_session *session, char **result, xen_vif vif); + #endif diff --git a/tools/libxen/src/xen_vif.c b/tools/libxen/src/xen_vif.c index bc9dd0dd2f..ac6147ff4f 100644 --- a/tools/libxen/src/xen_vif.c +++ b/tools/libxen/src/xen_vif.c @@ -575,3 +575,42 @@ xen_vif_get_uuid(xen_session *session, char **result, xen_vif vif) XEN_CALL_("VIF.get_uuid"); return session->ok; } + + +bool +xen_vif_set_security_label(xen_session *session, int64_t *result, xen_vif vif, + char *label, char *oldlabel) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vif }, + { .type = &abstract_type_string, + .u.string_val = label }, + { .type = &abstract_type_string, + .u.string_val = oldlabel }, + }; + + abstract_type result_type = abstract_type_int; + + *result = 0; + XEN_CALL_("VIF.set_security_label"); + return session->ok; +} + + +bool +xen_vif_get_security_label(xen_session *session, char **result, xen_vif vif) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vif }, + }; + + abstract_type result_type = abstract_type_string; + + *result = NULL; + XEN_CALL_("VIF.get_security_label"); + return session->ok; +} diff --git a/tools/python/xen/util/security.py b/tools/python/xen/util/security.py index 608ed463f2..5183ed2c98 100644 --- a/tools/python/xen/util/security.py +++ b/tools/python/xen/util/security.py @@ -831,7 +831,7 @@ def get_domain_resources(dominfo): Entries are strored in the following formats: tap:qcow:/path/xyz.qcow """ - resources = { 'vbd' : [], 'tap' : []} + resources = { 'vbd' : [], 'tap' : [], 'vif' : []} devs = dominfo.info['devices'] uuids = devs.keys() for uuid in uuids: @@ -839,6 +839,15 @@ def get_domain_resources(dominfo): typ = dev[0] if typ in [ 'vbd', 'tap' ]: resources[typ].append(dev[1]['uname']) + if typ in [ 'vif' ]: + sec_lab = dev[1].get('security_label') + if sec_lab: + resources[typ].append(sec_lab) + else: + resources[typ].append("%s:%s:%s" % + (xsconstants.ACM_POLICY_ID, + active_policy, + "unlabeled")) return resources @@ -874,23 +883,36 @@ def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel, dictionary of the resource name to resource label mappings under which the evaluation should be done. """ + def collect_labels(reslabels, s_label, polname): + if len(s_label) != 3 or polname != s_label[1]: + return False + label = s_label[2] + if not label in reslabels: + reslabels.append(label) + return True + resources = get_domain_resources(dominfo) reslabels = [] # all resource labels + polname = xspol.get_name() - for key in resources.keys(): - for res in resources[key]: - try: - tmp = access_control[res] - if len(tmp) != 3: + for key, value in resources.items(): + if key in [ 'vbd', 'tap' ]: + for res in resources[key]: + try: + label = access_control[res] + if not collect_labels(reslabels, label, polname): + return False + except: return False - - if polname != tmp[1]: + elif key in [ 'vif' ]: + for xapi_label in value: + label = xapi_label.split(":") + if not collect_labels(reslabels, label, polname): return False - label = tmp[2] - if not label in reslabels: - reslabels.append(label) - except: - return False + else: + log.error("Unhandled device type: %s" % key) + return False + # Check that all resource labes have a common STE type with the # vmlabel rc = xspol.policy_check_vmlabel_against_reslabels(vmlabel, reslabels) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 3d890e7c44..2192d334b5 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -2084,6 +2084,25 @@ class XendAPI(object): def VIF_get_security_label(self, session, vif_ref): return self._VIF_get(vif_ref, 'security_label') + def _VIF_set(self, ref, prop, val, old_val): + return XendDomain.instance().set_dev_property_by_uuid( + 'vif', ref, prop, val, old_val) + + def VIF_set_security_label(self, session, vif_ref, sec_lab, old_lab): + xendom = XendDomain.instance() + dom = xendom.get_vm_with_dev_uuid('vif', vif_ref) + if not dom: + return xen_api_error(['HANDLE_INVALID', 'VIF', vif_ref]) + + if dom._stateGet() == XEN_API_VM_POWER_STATE_RUNNING: + raise SecurityError(-xsconstants.XSERR_RESOURCE_IN_USE) + + rc = self._VIF_set(vif_ref, 'security_label', sec_lab, old_lab) + if rc == False: + raise SecurityError(-xsconstants.XSERR_BAD_LABEL) + return xen_api_success(xsconstants.XSERR_SUCCESS) + + # Xen API: Class VIF_metrics # ---------------------------------------------------------------- diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 4dac85061b..5bc40a5dfb 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -1085,6 +1085,12 @@ class XendConfig(dict): self.device_duplicate_check(dev_type, dev_info, target) + if dev_type == 'vif': + if dev_info.get('policy') and dev_info.get('label'): + dev_info['security_label'] = "%s:%s:%s" % \ + (xsconstants.ACM_POLICY_ID, + dev_info['policy'],dev_info['label']) + # create uuid if it doesn't exist dev_uuid = dev_info.get('uuid', None) if not dev_uuid: @@ -1159,6 +1165,10 @@ class XendConfig(dict): network = XendAPIStore.get( cfg_xenapi.get('network'), 'network') dev_info['bridge'] = network.get_name_label() + + if cfg_xenapi.get('security_label'): + dev_info['security_label'] = \ + cfg_xenapi.get('security_label') dev_uuid = cfg_xenapi.get('uuid', None) if not dev_uuid: diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index c951dc6af8..3d48365571 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -688,6 +688,29 @@ class XendDomain: return value + def set_dev_property_by_uuid(self, klass, dev_uuid, field, value, + old_val = None): + rc = True + self.domains_lock.acquire() + + try: + try: + dom = self.get_vm_with_dev_uuid(klass, dev_uuid) + if dom: + o_val = dom.get_dev_property(klass, dev_uuid, field) + log.info("o_val=%s, old_val=%s" % (o_val, old_val)) + if old_val and old_val != o_val: + return False + + dom.set_dev_property(klass, dev_uuid, field, value) + self.managed_config_save(dom) + except ValueError, e: + pass + finally: + self.domains_lock.release() + + return rc + def is_valid_vm(self, vm_ref): return (self.get_vm_by_uuid(vm_ref) != None) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index a69211d32b..94a02049a6 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -2420,6 +2420,8 @@ class XendDomainInfo: config['io_read_kbs'] = 0.0 config['io_write_kbs'] = 0.0 + config['security_label'] = config.get('security_label', '') + if dev_class == 'vbd': if self._stateGet() not in (XEN_API_VM_POWER_STATE_HALTED,): diff --git a/tools/python/xen/xend/XendXSPolicyAdmin.py b/tools/python/xen/xend/XendXSPolicyAdmin.py index 727cae664a..b3d7c2a9f1 100644 --- a/tools/python/xen/xend/XendXSPolicyAdmin.py +++ b/tools/python/xen/xend/XendXSPolicyAdmin.py @@ -312,6 +312,18 @@ class XSPolicyAdmin: vmlabel = pol.policy_get_domain_label_by_ssidref_formatted(ssidref) return vmlabel + def get_stes_of_vmlabel(self, vmlabel_xapi): + """ Get the list of STEs given a VM label in XenAPI format """ + stes = [] + loadedpol = self.get_loaded_policy() + if loadedpol: + tmp = vmlabel_xapi.split(":") + if len(tmp) != 3: + return [] + stes = loadedpol.policy_get_stes_of_vmlabel(tmp[2]) + return stes + + poladmin = None def XSPolicyAdminInstance(maxpolicies=1): diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 130668428c..3d4b598b91 100644 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -26,6 +26,11 @@ import re from xen.xend import XendOptions from xen.xend.server.DevController import DevController +from xen.xend.XendError import VmError +from xen.util import security +from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance + +from xen.xend.XendLogging import log xoptions = XendOptions.instance() @@ -108,6 +113,7 @@ class NetifController(DevController): ipaddr = config.get('ip') model = config.get('model') accel = config.get('accel') + sec_lab = config.get('security_label') if not typ: typ = xoptions.netback_type @@ -134,6 +140,8 @@ class NetifController(DevController): back['model'] = model if accel: back['accel'] = accel + if sec_lab: + back['security_label'] = sec_lab config_path = "device/%s/%d/" % (self.deviceClass, devid) for x in back: @@ -149,9 +157,34 @@ class NetifController(DevController): front = { 'handle' : "%i" % devid, 'mac' : mac } + if security.on(): + self.do_access_control(config) + return (devid, back, front) + def do_access_control(self, config): + """ do access control checking. Throws a VMError if access is denied """ + domain_label = self.vm.get_security_label() + stes = XSPolicyAdminInstance().get_stes_of_vmlabel(domain_label) + res_label = config.get('security_label') + if len(stes) > 1 or res_label: + if not res_label: + raise VmError("'VIF' must be labeled") + (label, ssidref, policy) = \ + security.security_label_to_details(res_label) + if domain_label: + rc = security.res_security_check_xapi(label, ssidref, + policy, + domain_label) + if rc == 0: + raise VmError("VM's access to network device denied. " + "Check labeling") + else: + raise VmError("VM must have a security label to access " + "network device") + + def getDeviceConfiguration(self, devid): """@see DevController.configuration""" @@ -160,10 +193,12 @@ class NetifController(DevController): config_path = "device/%s/%d/" % (self.deviceClass, devid) devinfo = () for x in ( 'script', 'ip', 'bridge', 'mac', - 'type', 'vifname', 'rate', 'uuid', 'model', 'accel'): + 'type', 'vifname', 'rate', 'uuid', 'model', 'accel', + 'security_label'): y = self.vm._readVm(config_path + x) devinfo += (y,) - (script, ip, bridge, mac, typ, vifname, rate, uuid, model, accel) = devinfo + (script, ip, bridge, mac, typ, vifname, rate, uuid, + model, accel, security_label) = devinfo if script: result['script'] = script @@ -185,5 +220,7 @@ class NetifController(DevController): result['model'] = model if accel: result['accel'] = accel - + if security_label: + result['security_label'] = security_label + return result diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py index 9e93641284..bb27d30331 100644 --- a/tools/python/xen/xm/addlabel.py +++ b/tools/python/xen/xm/addlabel.py @@ -34,6 +34,7 @@ def help(): Format: xm addlabel <label> dom <configfile> [<policy>] xm addlabel <label> mgt <domain name> [<policy type>:<policy>] xm addlabel <label> res <resource> [[<policy type>:]<policy>] + xm addlabel <label> vif-<idx> <domain name> [<policy type>:<policy>] This program adds an acm_label entry into the 'configfile' for a domain or allows to label a xend-managed domain. @@ -162,6 +163,32 @@ def add_domain_label_xapi(label, domainname, policyref, policy_type): print "Set the label of dormant domain '%s' to '%s'." % \ (domainname,label) +def add_vif_label(label, vmname, idx, policyref, policy_type): + if xm_main.serverType != xm_main.SERVER_XEN_API: + raise OptionError('Need to be configure for using xen-api.') + vm_refs = server.xenapi.VM.get_by_name_label(vmname) + if len(vm_refs) == 0: + raise OptionError('A VM with the name %s does not exist.' % + vmname) + vif_refs = server.xenapi.VM.get_VIFs(vm_refs[0]) + if len(vif_refs) <= idx: + raise OptionError("Bad VIF index.") + vif_ref = server.xenapi.VIF.get_by_uuid(vif_refs[idx]) + if not vif_ref: + print "Internal error: VIF does not exist." + sec_lab = "%s:%s:%s" % (policy_type, policyref, label) + try: + old_lab = server.xenapi.VIF.get_security_label(vif_ref) + rc = server.xenapi.VIF.set_security_label(vif_ref, + sec_lab, old_lab) + if int(rc) != 0: + print "Could not label the VIF." + else: + print "Successfully labeled the VIF." + except Exception, e: + print "Could not label the VIF: %s" % str(e) + + def main(argv): policyref = None policy_type = "" @@ -209,6 +236,20 @@ def main(argv): else: raise OptionError("Policy name in wrong format.") add_resource_label(label, resource, policyref, policy_type) + elif argv[2].lower().startswith("vif-"): + try: + idx = int(argv[2][4:]) + if idx < 0: + raise + except: + raise OptionError("Bad VIF device index.") + vmname = argv[3] + if policy_type == "": + tmp = policyref.split(":") + if len(tmp) != 2: + raise OptionError("Policy name in wrong format.") + policy_type, policyref = tmp + add_vif_label(label, vmname, idx, policyref, policy_type) else: raise OptionError('Need to specify either "dom", "mgt" or "res" as ' 'object to add label to.') diff --git a/tools/python/xen/xm/create.dtd b/tools/python/xen/xm/create.dtd index f9c7fe8957..efb3cbfd3e 100644 --- a/tools/python/xen/xm/create.dtd +++ b/tools/python/xen/xm/create.dtd @@ -74,7 +74,8 @@ mtu CDATA #REQUIRED device CDATA #REQUIRED qos_algorithm_type CDATA #REQUIRED - network CDATA #IMPLIED> + network CDATA #IMPLIED + security_label CDATA #IMPLIED> <!ELEMENT vtpm (name*)> <!ATTLIST vtpm backend CDATA #REQUIRED> diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index bca85abbde..f4d056608b 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -704,7 +704,8 @@ def configure_vifs(config_devs, vals): def f(k): if k not in ['backend', 'bridge', 'ip', 'mac', 'script', 'type', - 'vifname', 'rate', 'model', 'accel']: + 'vifname', 'rate', 'model', 'accel', + 'policy', 'label']: err('Invalid vif option: ' + k) config_vif.append([k, d[k]]) diff --git a/tools/python/xen/xm/getlabel.py b/tools/python/xen/xm/getlabel.py index 5954ca923b..cf7033d7d4 100644 --- a/tools/python/xen/xm/getlabel.py +++ b/tools/python/xen/xm/getlabel.py @@ -31,6 +31,7 @@ def help(): Usage: xm getlabel dom <configfile> xm getlabel mgt <domain name> xm getlabel res <resource> + xm getlabel vif-<idx> <vmname> This program shows the label for a domain, resource or virtual network interface of a Xend-managed domain.""" @@ -103,6 +104,22 @@ def get_domain_label(configfile): data = data.rstrip("\']") print "policytype=%s," % xsconstants.ACM_POLICY_ID + data +def get_vif_label(vmname, idx): + if xm_main.serverType != xm_main.SERVER_XEN_API: + raise OptionError('xm needs to be configure to use the xen-api.') + vm_refs = server.xenapi.VM.get_by_name_label(vmname) + if len(vm_refs) == 0: + raise OptionError('A VM with the name %s does not exist.' % + vmname) + vif_refs = server.xenapi.VM.get_VIFs(vm_refs[0]) + if len(vif_refs) <= idx: + raise OptionError("Bad VIF index.") + vif_ref = server.xenapi.VIF.get_by_uuid(vif_refs[idx]) + if not vif_ref: + print "No VIF with this UUID." + sec_lab = server.xenapi.VIF.get_security_label(vif_ref) + print "%s" % sec_lab + def get_domain_label_xapi(domainname): if xm_main.serverType != xm_main.SERVER_XEN_API: raise OptionError('xm needs to be configure to use the xen-api.') @@ -128,6 +145,15 @@ def main(argv): elif argv[1].lower() == "res": resource = argv[2] get_resource_label(resource) + elif argv[1].lower().startswith("vif-"): + try: + idx = int(argv[1][4:]) + if idx < 0: + raise + except: + raise OptionError("Bad VIF device index.") + vmname = argv[2] + get_vif_label(vmname, idx) else: raise OptionError('First subcommand argument must be "dom"' ', "mgt" or "res"') diff --git a/tools/python/xen/xm/rmlabel.py b/tools/python/xen/xm/rmlabel.py index 2eb9c4b6d4..c3c488fc5b 100644 --- a/tools/python/xen/xm/rmlabel.py +++ b/tools/python/xen/xm/rmlabel.py @@ -30,6 +30,7 @@ def help(): Example: xm rmlabel dom <configfile> xm rmlabel res <resource> xm rmlabel mgt <domain name> + xm rmlabel vif-<idx> <domain name> This program removes an acm_label entry from the 'configfile' for a domain, from a Xend-managed domain, from the global resource label @@ -129,24 +130,55 @@ def rm_domain_label_xapi(domainname): except Exception, e: print('Could not remove label from domain: %s' % e) +def rm_vif_label(vmname, idx): + if xm_main.serverType != xm_main.SERVER_XEN_API: + raise OptionError('Need to be configure for using xen-api.') + vm_refs = server.xenapi.VM.get_by_name_label(vmname) + if len(vm_refs) == 0: + raise OptionError('A VM with the name %s does not exist.' % + vmname) + vif_refs = server.xenapi.VM.get_VIFs(vm_refs[0]) + if len(vif_refs) <= idx: + raise OptionError("Bad VIF index.") + vif_ref = server.xenapi.VIF.get_by_uuid(vif_refs[idx]) + if not vif_ref: + print "A VIF with this UUID does not exist." + try: + old_lab = server.xenapi.VIF.get_security_label(vif_ref) + rc = server.xenapi.VIF.set_security_label(vif_ref, "", old_lab) + if int(rc) != 0: + print "Could not remove the label from the VIF." + else: + print "Successfully removed the label from the VIF." + except Exception, e: + print "Could not remove the label the VIF: %s" % str(e) + def main (argv): if len(argv) != 3: raise OptionError('Requires 2 arguments') - if argv[1].lower() not in ('dom', 'mgt', 'res'): - raise OptionError('Unrecognised type argument: %s' % argv[1]) - if argv[1].lower() == "dom": configfile = argv[2] rm_domain_label(configfile) elif argv[1].lower() == "mgt": domain = argv[2] rm_domain_label_xapi(domain) + elif argv[1].lower().startswith("vif-"): + try: + idx = int(argv[1][4:]) + if idx < 0: + raise + except: + raise OptionError("Bad VIF device index.") + vmname = argv[2] + rm_vif_label(vmname, idx) elif argv[1].lower() == "res": resource = argv[2] rm_resource_label(resource) + else: + raise OptionError('Unrecognised type argument: %s' % argv[1]) if __name__ == '__main__': try: diff --git a/tools/python/xen/xm/xenapi_create.py b/tools/python/xen/xm/xenapi_create.py index 0a2d74a209..70c91140b7 100644 --- a/tools/python/xen/xm/xenapi_create.py +++ b/tools/python/xen/xm/xenapi_create.py @@ -440,7 +440,9 @@ class xenapi_create: vif.attributes["qos_algorithm_type"].value, "qos_algorithm_params": get_child_nodes_as_dict(vif, - "qos_algorithm_param", "key", "value") + "qos_algorithm_param", "key", "value"), + "security_label": + vif.attributes["security_label"].value } return server.xenapi.VIF.create(vif_record) @@ -748,6 +750,15 @@ class sxp2xml: vif.attributes["device"] = dev vif.attributes["qos_algorithm_type"] = "" + policy = get_child_by_name(vif_sxp, "policy") + label = get_child_by_name(vif_sxp, "label") + + if label and policy: + vif.attributes["security_label"] \ + = "%s:%s:%s" % (xsconstants.ACM_POLICY_ID, policy, label) + else: + vif.attributes["security_label"] = "" + if get_child_by_name(vif_sxp, "bridge") is not None: vif.attributes["network"] \ = get_child_by_name(vif_sxp, "bridge") |