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: - return False - if polname != tmp[1]: + polname = xspol.get_name() + 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 - label = tmp[2] - if not label in reslabels: - reslabels.append(label) - except: - return False + elif key in [ 'vif' ]: + for xapi_label in value: + label = xapi_label.split(":") + if not collect_labels(reslabels, label, polname): + 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