diff --git a/docs/man/xm.pod.1 b/docs/man/xm.pod.1 index 72932dee93..3e98fadc9c 100644 --- a/docs/man/xm.pod.1 +++ b/docs/man/xm.pod.1 @@ -821,15 +821,13 @@ security in Xen, you must compile Xen with ACM support enabled as described under "Configuring Security" below. There, you will find also examples of each subcommand described here. -=item B ACM I I<[--load|--boot]> +=item B ACM I Makes the given ACM policy available to xend as a I. The policy is compiled and a mapping (.map) as well as a binary (.bin) -version of the policy is created. If the option I<--load> is provided -the policy is loaded into Xen. If the option I<--boot> is provided the -system is configure to be loaded with the policy at boot time. If these -options are not provided with the B subcommand, the -B subcommand provides this functionality. +version of the policy is created. The policy is loaded and the system's +bootloader is prepared to boot the system with this policy the next time +it is started. =over 4 @@ -844,16 +842,13 @@ global policy root directory. =back -=item B I<[--load|--boot]> +=item B -Activates the xend-managed policy by loading it into Xen using the -I<--load> option or configures the system to boot with the -xend-managed policy during the next reboot as a result of the -I<--boot> option. The latter is only supported if the system is booted -with the grub boot loader and the default boot title is modified. -It copies the binary policy representation into the /boot directory and -adds a module line specifying the binary policy to the /boot/grub/menu.lst -or /boot/grub/grub.conf file. +Reset the system's policy to the default state where the DEFAULT policy +is loaded and enforced. This operation may fail if for example guest VMs are +running and and one of them uses a different label than what Domain-0 +does. It is best to make sure that no guests are running before issuing +this command. =item B [--dumpxml] @@ -938,50 +933,42 @@ B In xen_source_dir/Config.mk set the following parameter: + XSM_ENABLE ?= y ACM_SECURITY ?= y + Then recompile and install xen and the security tools and then reboot: - cd xen_source_dir/xen; make clean; make; cp xen.gz /boot; - cd xen_source_dir/tools/security; make install; + cd xen_source_dir; make clean; make install reboot into Xen =back +B + +=over 4 + +To set the system's security policy enforcement into its default state, +the follow command can be issued. Make sure that no guests are running +while doing this. + + xm resetpolicy + +After this command has successfully completed, the system's DEFAULT policy +is enforced. + +=back + B =over 4 -This step makes the policy available to xend and creates the client_v1.map and -client_v1.bin files in /etc/xen/acm-security/policies/example/chwall_ste. +This step sets the system's policy and automatically loads it into Xen +for enforcement. xm setpolicy ACM example.client_v1 =back -B - -=over 4 - -This step activates the xend-manged policy as new security policy in Xen. -You can use the dumppolicy subcommand before and afterwards to see the -change in the Xen policy state. - - xm activatpolicy --load - -=back - -B - -=over 4 - -This configures the boot loader to load the current xend-managed policy at -boot time. During system start, the ACM configures Xen with this policy and -Xen enforces this policy from then on. - - xm activatepolicy --boot - -=back - B =over 4 diff --git a/tools/python/xen/util/acmpolicy.py b/tools/python/xen/util/acmpolicy.py index 3f247d2a52..13bcda377a 100644 --- a/tools/python/xen/util/acmpolicy.py +++ b/tools/python/xen/util/acmpolicy.py @@ -51,6 +51,19 @@ ACM_SCHEMA_FILE = ACM_POLICIES_DIR + "security_policy.xsd" ACM_LABEL_UNLABELED = "__UNLABELED__" ACM_LABEL_UNLABELED_DISPLAY = "unlabeled" +""" + Error codes reported in when trying to test for a new policy + These error codes are reported in an array of tuples where + each error code is followed by a parameter describing the error + more closely, such as a domain id. +""" +ACM_EVTCHN_SHARING_VIOLATION = 0x100 +ACM_GNTTAB_SHARING_VIOLATION = 0x101 +ACM_DOMAIN_LOOKUP = 0x102 +ACM_CHWALL_CONFLICT = 0x103 +ACM_SSIDREF_IN_USE = 0x104 + + class ACMPolicy(XSPolicy): """ ACMPolicy class. Implements methods for getting information from @@ -228,7 +241,7 @@ class ACMPolicy(XSPolicy): return -xsconstants.XSERR_BAD_LABEL, errors #Get binary and map from the new policy - rc, map, bin_pol = acmpol_new.policy_create_map_and_bin() + rc, pol_map, bin_pol = acmpol_new.policy_create_map_and_bin() if rc != xsconstants.XSERR_SUCCESS: log.error("Could not build the map and binary policy.") return rc, errors @@ -356,7 +369,7 @@ class ACMPolicy(XSPolicy): pass return ssidref - def set_vm_bootlabel(self, vm_label): + def set_vm_bootlabel(self, vm_label, remove=False): parms="<>" if vm_label != "": ssidref = self.vmlabel_to_ssidref(vm_label) @@ -367,6 +380,10 @@ class ACMPolicy(XSPolicy): self.get_name(),vm_label) else: ssidref = 0 #Identifier for removal + + if remove == True: + parms = "<>" + try: def_title = bootloader.get_default_title() bootloader.set_kernel_attval(def_title, "ssidref", parms) @@ -387,7 +404,7 @@ class ACMPolicy(XSPolicy): if name: p = name.split(".") path = "" - if dotted == True: + if dotted: sep = "." else: sep = "/" @@ -513,8 +530,8 @@ class ACMPolicy(XSPolicy): self.set_frompolicy_name(curpol.policy_dom_get_hdr_item("PolicyName")) version = curpol.policy_dom_get_hdr_item("Version") self.set_frompolicy_version(version) - (maj, min) = self.__convVersionToTuple(version) - self.set_policy_version("%s.%s" % (maj, min+1)) + (maj, minor) = self.__convVersionToTuple(version) + self.set_policy_version("%s.%s" % (maj, minor+1)) # # Get all types that are part of a node @@ -877,8 +894,7 @@ class ACMPolicy(XSPolicy): """ Determine whether this policy is the active one. """ - security.refresh_security_policy() - if self.get_name() == security.active_policy: + if self.get_name() == security.get_active_policy_name(): return True return False diff --git a/tools/python/xen/util/xsm/acm/acm.py b/tools/python/xen/util/xsm/acm/acm.py index 47e9ce586d..d8f4be4314 100644 --- a/tools/python/xen/util/xsm/acm/acm.py +++ b/tools/python/xen/util/xsm/acm/acm.py @@ -24,6 +24,7 @@ import os, string, re import threading import struct import stat +import base64 from xen.lowlevel import acm from xen.xend import sxp from xen.xend import XendConstants @@ -39,7 +40,6 @@ policy_dir_prefix = security_dir_prefix + "/policies" res_label_filename = policy_dir_prefix + "/resource_labels" boot_filename = "/boot/grub/menu.lst" altboot_filename = "/boot/grub/grub.conf" -xensec_xml2bin = "/usr/sbin/xensec_xml2bin" xensec_tool = "/usr/sbin/xensec_tool" #global patterns for map file @@ -49,7 +49,7 @@ secondary_entry_re = re.compile("\s*SECONDARY\s+.*", re.IGNORECASE) label_template_re = re.compile(".*security_label_template.xml", re.IGNORECASE) mapping_filename_re = re.compile(".*\.map", re.IGNORECASE) policy_reference_entry_re = re.compile("\s*POLICYREFERENCENAME\s+.*", re.IGNORECASE) -vm_label_re = re.compile("\s*LABEL->SSID\s+VM\s+.*", re.IGNORECASE) +vm_label_re = re.compile("\s*LABEL->SSID\s.+[VM|ANY]\s+.*", re.IGNORECASE) res_label_re = re.compile("\s*LABEL->SSID\s+RES\s+.*", re.IGNORECASE) all_label_re = re.compile("\s*LABEL->SSID\s+.*", re.IGNORECASE) access_control_re = re.compile("\s*access_control\s*=", re.IGNORECASE) @@ -77,9 +77,25 @@ __resfile_lock = threading.RLock() log = logging.getLogger("xend.util.security") + +#Functions exported through XML-RPC +xmlrpc_exports = [ + 'set_resource_label', + 'get_resource_label', + 'list_labels', + 'get_labeled_resources', + 'set_policy', + 'get_policy', + 'activate_policy', + 'rm_bootpolicy', + 'get_xstype', + 'get_domain_label', + 'set_domain_label' +] + # Our own exception definition. It is masked (pass) if raised and # whoever raises this exception must provide error information. -class ACMError(Exception): +class XSMError(Exception): def __init__(self,value): self.value = value def __str__(self): @@ -90,7 +106,7 @@ class ACMError(Exception): def err(msg): """Raise ACM exception. """ - raise ACMError(msg) + raise XSMError(msg) @@ -118,12 +134,17 @@ def refresh_security_policy(): global active_policy active_policy = 'INACCESSIBLE' + if os.access("/proc/xen/privcmd", os.R_OK|os.W_OK): try: active_policy = acm.policy() except: active_policy = "INACTIVE" +def get_active_policy_name(): + refresh_security_policy() + return active_policy + # now set active_policy refresh_security_policy() @@ -132,8 +153,7 @@ def on(): returns none if security policy is off (not compiled), any string otherwise, use it: if not security.on() ... """ - refresh_security_policy() - return (active_policy not in ['INACTIVE', 'NULL']) + return (get_active_policy_name() not in ['INACTIVE', 'NULL']) def calc_dom_ssidref_from_info(info): @@ -158,11 +178,10 @@ def calc_dom_ssidref_from_info(info): typ, policyname, vmlabel = seclab.split(":") if typ != xsconstants.ACM_POLICY_ID: raise VmError("Policy type '%s' must be changed." % typ) - refresh_security_policy() - if active_policy != policyname: + if get_active_policy_name() != policyname: raise VmError("Active policy '%s' different than " "what in VM's label ('%s')." % - (active_policy, policyname)) + (get_active_policy_name(), policyname)) ssidref = label2ssidref(vmlabel, policyname, "dom") return ssidref else: @@ -180,7 +199,7 @@ def getmapfile(policyname): 4. True if policy file is available, False otherwise """ if not policyname: - policyname = active_policy + policyname = get_active_policy_name() map_file_ok = False primary = None secondary = None @@ -199,8 +218,7 @@ def getmapfile(policyname): if not os.path.isfile(policy_filename): err("Policy file \'" + policy_filename + "\' not found.") else: - err("Mapping file \'" + map_filename + "\' not found." + - " Use xm makepolicy to create it.") + err("Mapping file \'" + map_filename + "\' not found.") f = open(map_filename) for line in f: @@ -221,7 +239,7 @@ def getmapfile(policyname): if map_file_ok and primary and secondary: return (primary, secondary, f, True) else: - err("Mapping file inconsistencies found. Try makepolicy to create a new one.") + err("Mapping file inconsistencies found.") @@ -253,10 +271,10 @@ def ssidref2label(ssidref_var): (primary, secondary, f, pol_exists) = getmapfile(None) if not f: if (pol_exists): - err("Mapping file for policy not found.\n" + - "Please use makepolicy command to create mapping file!") + err("Mapping file for policy not found.") else: - err("Policy file for \'" + active_policy + "\' not found.") + err("Policy file for \'" + get_active_policy_name() + + "\' not found.") #2. get labelnames for both ssidref parts pri_ssid = ssidref & 0xffff @@ -534,37 +552,99 @@ def hv_get_policy(): return rc, bin_pol -def make_policy(policy_name): - policy_file = string.join(string.split(policy_name, "."), "/") - if not os.path.isfile(policy_dir_prefix + "/" + policy_file + "-security_policy.xml"): - err("Unknown policy \'" + policy_name + "\'") +def set_policy(xs_type, xml, flags, overwrite): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendXSPolicyAdmin + xspoladmin = XendXSPolicyAdmin.XSPolicyAdminInstance() + try: + acmpol, rc, errors = \ + xspoladmin.add_acmpolicy_to_system(xml, + int(flags), + True) + return rc, base64.b64encode(errors) + except Exception, e: + err(str(e)) - (ret, output) = commands.getstatusoutput(xensec_xml2bin + " -d " + policy_dir_prefix + " " + policy_file) - if ret: - err("Creating policy failed:\n" + output) -def load_policy(policy_name): - global active_policy - policy_file = policy_dir_prefix + "/" + string.join(string.split(policy_name, "."), "/") - if not os.path.isfile(policy_file + ".bin"): - if os.path.isfile(policy_file + "-security_policy.xml"): - err("Binary file does not exist." + - "Please use makepolicy to build the policy binary.") - else: - err("Unknown Policy " + policy_name) +def get_policy(): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendXSPolicyAdmin + poladmin = XendXSPolicyAdmin.XSPolicyAdminInstance() + try: + policy = poladmin.get_loaded_policy() + if policy != None: + return policy.toxml(), poladmin.get_policy_flags(policy) + except Exception, e: + err(str(e)) + return "", 0 - #require this policy to be the first or the same as installed - if active_policy not in ['DEFAULT', policy_name]: - err("Active policy \'" + active_policy + - "\' incompatible with new policy \'" + policy_name + "\'") - (ret, output) = commands.getstatusoutput(xensec_tool + " loadpolicy " + policy_file + ".bin") - if ret: - err("Loading policy failed:\n" + output) +def activate_policy(flags): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendXSPolicyAdmin + poladmin = XendXSPolicyAdmin.XSPolicyAdminInstance() + try: + policies = poladmin.get_policies() + if len(policies) > 0: + flags = int(flags) + irc = poladmin.activate_xspolicy(policies[0], flags) + return irc + except Exception, e: + err("Error while activating the policy: " % str(e)) + return 0 + + +def rm_bootpolicy(): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendXSPolicyAdmin + rc = XendXSPolicyAdmin.XSPolicyAdminInstance().rm_bootpolicy() + if rc != xsconstants.XSERR_SUCCESS: + err("Error while removing boot policy: %s" % \ + str(xsconstants.xserr2string(-rc))) + return rc + + +def get_xstype(): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendXSPolicyAdmin + return XendXSPolicyAdmin.XSPolicyAdminInstance().isXSEnabled() + + +def get_domain_label(domain): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendDomain + dom = XendDomain.instance().domain_lookup_nr(domain) + if dom: + seclab = dom.get_security_label() + return seclab else: - # refresh active policy - refresh_security_policy() + err("Domain not found.") +def set_domain_label(domain, seclab, old_seclab): + """ + Xend exports this function via XML-RPC + """ + from xen.xend import XendDomain + dom = XendDomain.instance().domain_lookup_nr(domain) + if dom: + results = dom.set_security_label(seclab, old_seclab) + rc, errors, old_label, new_ssidref = results + return rc, new_ssidref + else: + err("Domain not found.") + def dump_policy(): if active_policy in ['NULL', 'INACTIVE', 'INACCESSIBLE' ]: @@ -589,16 +669,32 @@ def dump_policy_file(filename, ssidref=None): print output -def list_labels(policy_name, condition): - if (not policy_name) and active_policy in \ - [ 'NULL', 'INACTIVE', 'DEFAULT', 'INACCESSIBLE' ]: - err("Current policy \'" + active_policy + "\' has no labels defined.\n") +def list_labels(policy_name, ltype): + """ + Xend exports this function via XML-RPC + + List the VM,resource or any kind of labels contained in the + given policy. If no policy name is given, the currently + active policy's label will be returned if they exist. + """ + if not policy_name: + if active_policy in [ 'NULL', 'INACTIVE', "" ]: + err("Current policy \'" + active_policy + "\' " + "has no labels defined.\n") + + if not ltype or ltype == 'dom': + condition = vm_label_re + elif ltype == 'res': + condition = res_label_re + elif ltype == 'any': + condition = all_label_re + else: + err("Unknown label type \'" + ltype + "\'") (primary, secondary, f, pol_exists) = getmapfile(policy_name) if not f: if pol_exists: - err("Cannot find mapfile for policy \'" + policy_name + - "\'.\nPlease use makepolicy to create mapping file.") + err("Cannot find mapfile for policy \'" + policy_name + "\'.\n") else: err("Unknown policy \'" + policy_name + "\'") @@ -608,6 +704,10 @@ def list_labels(policy_name, condition): label = line.split()[3] if label not in labels: labels.append(label) + + if '__NULL_LABEL__' in labels: + labels.remove('__NULL_LABEL__') + return labels @@ -763,10 +863,10 @@ def res_security_check(resource, domain_label): # provide descriptive error messages if decision == 'DENIED': if label == ssidref2label(NULL_SSIDREF): - raise ACMError("Resource '"+resource+"' is not labeled") + raise XSMError("Resource '"+resource+"' is not labeled") rtnval = 0 else: - raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed") + raise XSMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed") rtnval = 0 # security is off, make sure resource isn't labeled @@ -775,7 +875,7 @@ def res_security_check(resource, domain_label): # xm without ACM are free to use relative paths. (policytype, label, policy) = get_res_label(resource) if policy != 'NULL': - raise ACMError("Security is off, but '"+resource+"' is labeled") + raise XSMError("Security is off, but '"+resource+"' is labeled") rtnval = 0 return rtnval @@ -803,10 +903,10 @@ def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label): # provide descriptive error messages if decision == 'DENIED': if rlabel == ssidref2label(NULL_SSIDREF): - #raise ACMError("Resource is not labeled") + #raise XSMError("Resource is not labeled") rtnval = 0 else: - #raise ACMError("Permission denied for resource because label '"+rlabel+"' is not allowed") + #raise XSMError("Permission denied for resource because label '"+rlabel+"' is not allowed") rtnval = 0 # security is off, make sure resource isn't labeled @@ -814,17 +914,35 @@ def res_security_check_xapi(rlabel, rssidref, rpolicy, xapi_dom_label): # Note, we can't canonicalise the resource here, because people using # xm without ACM are free to use relative paths. if rpolicy != 'NULL': - #raise ACMError("Security is off, but resource is labeled") + #raise XSMError("Security is off, but resource is labeled") rtnval = 0 return rtnval -def validate_label(label, policyref): +def validate_label_xapi(xapi_label, dom_or_res): + """ + Make sure that this label is part of the currently enforced policy + and that it references the current policy. + dom_or_res defines whether this is a VM ('res') or resource label + ('res') + """ + tmp = xapi_label.split(":") + if len(tmp) != 3: + return -xsconstants.XSERR_BAD_LABEL_FORMAT + policytyp, policyref, label = tmp + return validate_label(policytyp, policyref, label, dom_or_res) + + +def validate_label(policytype, policyref, label, dom_or_res): """ Make sure that this label is part of the currently enforced policy and that it reference the current policy. """ + if policytype != xsconstants.ACM_POLICY_ID: + return -xsconstants.XSERR_WRONG_POLICY_TYPE + if not policytype or not label: + return -xsconstants.XSERR_BAD_LABEL_FORMAT rc = xsconstants.XSERR_SUCCESS from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance curpol = XSPolicyAdminInstance().get_loaded_policy() @@ -832,7 +950,7 @@ def validate_label(label, policyref): rc = -xsconstants.XSERR_BAD_LABEL else: try: - label2ssidref(label, curpol.get_name() , 'res') + label2ssidref(label, curpol.get_name() , dom_or_res) except: rc = -xsconstants.XSERR_BAD_LABEL return rc @@ -851,11 +969,11 @@ def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi): olabel = "" if reslabel_xapi == "": return rm_resource_label(resource, oldlabel_xapi) - typ, policyref, label = reslabel_xapi.split(":") - if typ != xsconstants.ACM_POLICY_ID: - return -xsconstants.XSERR_WRONG_POLICY_TYPE - if not policyref or not label: - return -xsconstants.XSERR_BAD_LABEL_FORMAT + + rc = validate_label_xapi(reslabel_xapi, 'res') + if rc != xsconstants.XSERR_SUCCESS: + return rc + if oldlabel_xapi not in [ "" ]: tmp = oldlabel_xapi.split(":") if len(tmp) != 3: @@ -866,9 +984,7 @@ def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi): otyp != xsconstants.INVALID_POLICY_PREFIX + \ xsconstants.ACM_POLICY_ID: return -xsconstants.XSERR_WRONG_POLICY_TYPE - rc = validate_label(label, policyref) - if rc != xsconstants.XSERR_SUCCESS: - return rc + typ, policyref, label = reslabel_xapi.split(":") return set_resource_label(resource, typ, policyref, label, olabel) @@ -1033,7 +1149,10 @@ def __resources_compatible_with_vmlabel(xspol, dominfo, vmlabel, def set_resource_label(resource, policytype, policyref, reslabel, \ oreslabel = None): - """Assign a label to a resource + """ + Xend exports this function via XML-RPC. + + Assign a label to a resource If the old label (oreslabel) is given, then the resource must have that old label. A resource label may be changed if @@ -1046,6 +1165,10 @@ def set_resource_label(resource, policytype, policyref, reslabel, \ @rtype: int @return Success (0) or failure value (< 0) """ + + if reslabel != "": + ssidref = label2ssidref(reslabel, policyref, 'res') + try: resource = unify_resname(resource, mustexist=False) except Exception: @@ -1123,7 +1246,10 @@ def format_resource_label(res): return "" def get_resource_label(resource): - """Get the assigned resource label of a given resource + """ + Xend exports this function via XML-RPC. + + Get the assigned resource label of a given resource @param resource: The name of a resource, i.e., "phy:/dev/hda" @rtype: list @@ -1161,7 +1287,10 @@ def get_labeled_resources_xapi(): def get_labeled_resources(): - """Get a map of all labeled resources + """ + Xend exports this function via XML-RPC + + Get a map of all labeled resources. @rtype: list @return list of labeled resources """ @@ -1225,6 +1354,7 @@ def change_acm_policy(bin_pol, del_array, chg_array, This function should be called with the lock to the domains held (XendDomain.instance().domains_lock) """ + from xen.util.acmpolicy import ACM_LABEL_UNLABELED rc = xsconstants.XSERR_SUCCESS domain_label_map = {} @@ -1266,14 +1396,25 @@ def change_acm_policy(bin_pol, del_array, chg_array, continue # label been renamed or deleted? - if reslabel_map.has_key(label) and cur_policyname == policy: + if policytype != xsconstants.ACM_POLICY_ID: + continue + elif reslabel_map.has_key(label) and cur_policyname == policy: + # renaming of an active label; policy may have been renamed label = reslabel_map[label] + polname = new_policyname elif label not in polnew_reslabels: + # label been removed policytype = xsconstants.INVALID_POLICY_PREFIX + policytype run_resource_label_change_script(key, "", "remove") + polname = policy + else: + # no change to label + policytype = xsconstants.ACM_POLICY_ID + polname = new_policyname + # Update entry access_control[key] = \ - tuple([ policytype, new_policyname, label ]) + tuple([ policytype, polname, label ]) # All resources have new labels in the access_control map # There may still be labels in there that are invalid now. @@ -1297,11 +1438,19 @@ def change_acm_policy(bin_pol, del_array, chg_array, new_vmlabel = vmlabel if vmlabel_map.has_key(vmlabel): + # renaming of the label new_vmlabel = vmlabel_map[vmlabel] - if new_vmlabel not in polnew_vmlabels: + polname = new_policyname + elif new_vmlabel not in polnew_vmlabels and \ + vmlabel != ACM_LABEL_UNLABELED: + # removal of VM label and not the 'unlabeled' label policytype = xsconstants.INVALID_POLICY_PREFIX + policytype + polname = policy + else: + polname = new_policyname + new_seclab = "%s:%s:%s" % \ - (policytype, new_policyname, new_vmlabel) + (policytype, polname, new_vmlabel) domain_label_map[dominfo] = [ sec_lab, new_seclab ] @@ -1383,16 +1532,20 @@ def get_security_label(self, xspol=None): return label def run_resource_label_change_script(resource, label, command): - script = XendOptions.instance().get_resource_label_change_script() - if script: - parms = { - 'resource' : resource, - 'label' : label, - 'command' : command, - } - log.info("Running resource label change script %s: %s" % - (script, parms)) - parms.update(os.environ) - os.spawnve(os.P_NOWAIT, script[0], script, parms) - else: - log.info("No script given for relabeling of resources.") + def __run_resource_label_change_script(label, command): + script = XendOptions.instance().get_resource_label_change_script() + if script: + parms = { + 'resource' : resource, + 'label' : label, + 'command' : command, + } + log.info("Running resource label change script %s: %s" % + (script, parms)) + parms.update(os.environ) + os.spawnve(os.P_WAIT, script[0], script, parms) + else: + log.info("No script given for relabeling of resources.") + thread = threading.Thread(target=__run_resource_label_change_script, + args=(label,command)) + thread.start() diff --git a/tools/python/xen/util/xsm/dummy/dummy.py b/tools/python/xen/util/xsm/dummy/dummy.py index 42a41b36c9..7a07e906d0 100644 --- a/tools/python/xen/util/xsm/dummy/dummy.py +++ b/tools/python/xen/util/xsm/dummy/dummy.py @@ -1,4 +1,6 @@ import sys +from xen.util import xsconstants +from xen.xend.XendLogging import log class XSMError(Exception): def __init__(self,value): @@ -6,11 +8,27 @@ class XSMError(Exception): def __str__(self): return repr(self.value) + security_dir_prefix = ""; policy_dir_prefix = ""; active_policy = ""; NULL_SSIDREF = 0; +#Functions exported through XML-RPC +xmlrpc_exports = [ + 'set_resource_label', + 'get_resource_label', + 'list_labels', + 'get_labeled_resources', + 'set_policy', + 'get_policy', + 'activate_policy', + 'rm_bootpolicy', + 'get_xstype', + 'get_domain_label', + 'set_domain_label' +] + def err(msg): """Raise XSM-dummy exception. """ @@ -45,7 +63,7 @@ def calc_dom_ssidref_from_info(info): return "" def set_security_label(policy, label): - return "" + return "" def ssidref2security_label(ssidref): return "" @@ -55,3 +73,49 @@ def has_authorization(ssidref): def get_security_label(self, xspol=None): return "" + +def get_resource_label_xapi(resource): + return "" + +def get_labeled_resources_xapi(): + return {} + +def set_resource_label_xapi(resource, reslabel_xapi, oldlabel_xapi): + err("Command not supported under XSM 'dummy' module.") + +def format_resource_label(res): + return "" + +def set_resource_label(resource, policytype, policyref, reslabel, + oreslabel = None): + err("Command not supported under XSM 'dummy' module.") + +def get_resource_label(resource): + return "" + +def list_labels(policy_name, ltype): + return [] + +def get_labeled_resources(): + return {} + +def set_policy(xs_type, xml, flags, overwrite): + err("Command not supported under xsm 'dummy' module.") + +def get_policy(): + return "", 0 + +def activate_policy(): + err("Command not supported under xsm 'dummy' module.") + +def rm_bootpolicy(): + err("Command not supported under xsm 'dummy' module.") + +def get_xstype(): + return 0 + +def get_domain_label(domain): + return "" + +def set_domain_label(): + err("Command not supported under xsm 'dummy' module.") diff --git a/tools/python/xen/util/xsm/flask/flask.py b/tools/python/xen/util/xsm/flask/flask.py index a0f931b364..933f0898c8 100644 --- a/tools/python/xen/util/xsm/flask/flask.py +++ b/tools/python/xen/util/xsm/flask/flask.py @@ -2,6 +2,9 @@ import sys from xen.lowlevel import flask from xen.xend import sxp +#Functions exported through XML-RPC +xmlrpc_exports = [ ] + def err(msg): """Raise XSM-Flask exception. """ diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index d43355d2ba..bdd8e6dff6 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -647,11 +647,18 @@ class XendConfig(dict): except ValueError, e: raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e)) - if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'): - cfg['security'] = sxp.child_value(sxp_cfg, 'security') - if 'security' in cfg and not cfg.get('security_label'): - secinfo = cfg['security'] - if isinstance(secinfo, list): + import xen.util.xsm.xsm as security + if security.on(): + from xen.util.acmpolicy import ACM_LABEL_UNLABELED + if not 'security' in cfg and sxp.child_value(sxp_cfg, 'security'): + cfg['security'] = sxp.child_value(sxp_cfg, 'security') + elif not cfg.get('security_label'): + cfg['security'] = [['access_control', + ['policy', security.get_active_policy_name() ], + ['label', ACM_LABEL_UNLABELED ]]] + + if 'security' in cfg and not cfg.get('security_label'): + secinfo = cfg['security'] # The xm command sends a list formatted like this: # [['access_control', ['policy', 'xm-test'],['label', 'red']], # ['ssidref', 196611]] @@ -664,12 +671,16 @@ class XendConfig(dict): policy = secinfo[idx][aidx][1] if secinfo[idx][aidx][0] == "label": label = secinfo[idx][aidx][1] - import xen.util.xsm.xsm as security cfg['security_label'] = \ security.set_security_label(policy, label) if not sxp.child_value(sxp_cfg, 'security_label'): del cfg['security'] + sec_lab = cfg['security_label'].split(":") + if len(sec_lab) != 3: + raise XendConfigError("Badly formatted security label: %s" + % cfg['security_label']) + old_state = sxp.child_value(sxp_cfg, 'state') if old_state: for i in range(len(CONFIG_OLD_DOM_STATES)): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index eaee766cf0..4558a9cec6 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -2460,12 +2460,14 @@ class XendDomainInfo: self, label): return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) - #Check label against expected one. - old_label = self.get_security_label(xspol_old) - if old_label != old_seclab: - log.info("old_label != old_seclab: %s != %s" % - (old_label, old_seclab)) - return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) + #Check label against expected one. Can only do this + # if the policy hasn't changed underneath in the meantime + if xspol_old == None: + old_label = self.get_security_label() + if old_label != old_seclab: + log.info("old_label != old_seclab: %s != %s" % + (old_label, old_seclab)) + return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) # relabel domain in the hypervisor rc, errors = security.relabel_domains([[domid, new_ssidref]]) @@ -2477,6 +2479,7 @@ class XendDomainInfo: # HALTED, RUNNING or PAUSED if domid == 0: if xspol: + self.info['security_label'] = seclab ssidref = poladmin.set_domain0_bootlabel(xspol, label) else: return (-xsconstants.XSERR_POLICY_NOT_LOADED, "", "", 0) @@ -2488,6 +2491,7 @@ class XendDomainInfo: return (-xsconstants.XSERR_BAD_LABEL, "", "", 0) self.info['security_label'] = seclab + try: xen.xend.XendDomain.instance().managed_config_save(self) except: diff --git a/tools/python/xen/xend/XendXSPolicyAdmin.py b/tools/python/xen/xend/XendXSPolicyAdmin.py index 2ca9f30096..d762bc8c4a 100644 --- a/tools/python/xen/xend/XendXSPolicyAdmin.py +++ b/tools/python/xen/xend/XendXSPolicyAdmin.py @@ -99,9 +99,10 @@ class XSPolicyAdmin: # This is meant as an update to a currently loaded policy if flags & xsconstants.XS_INST_LOAD == 0: raise SecurityError(-xsconstants.XSERR_POLICY_LOADED) + if flags & xsconstants.XS_INST_BOOT == 0: + self.rm_bootpolicy() rc, errors = loadedpol.update(xmltext) if rc == 0: - self.rm_bootpolicy() irc = self.activate_xspolicy(loadedpol, flags) # policy is loaded; if setting the boot flag fails it's ok. return (loadedpol, rc, errors) @@ -279,8 +280,7 @@ class XSPolicyAdmin: return None def get_hv_loaded_policy_name(self): - security.refresh_security_policy() - return security.active_policy + return security.get_active_policy_name() def get_policy_by_name(self, name): for pol in self.xsobjs.values(): @@ -300,8 +300,10 @@ class XSPolicyAdmin: return title def set_domain0_bootlabel(self, xspol, label): - """ Set the domain-0 bootlabel under the given policy """ - return xspol.set_vm_bootlabel(label) + """ Set the domain-0 bootlabel under the given policy. If the + current policy is the default policy, it will remove it. """ + rm_entry = (xspol.get_name() == "DEFAULT") + return xspol.set_vm_bootlabel(label, rm_entry) def rm_domain0_bootlabel(self): """ Remove the domain-0 bootlabel from the default boot title """ diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py index 91eb21632d..6aad3df9bd 100644 --- a/tools/python/xen/xend/server/XMLRPCServer.py +++ b/tools/python/xen/xend/server/XMLRPCServer.py @@ -207,6 +207,12 @@ class XMLRPCServer: self.server.register_function(domain_create, 'xend.domain.create') self.server.register_function(domain_restore, 'xend.domain.restore') + # A couple of the security functions + from xen.util.xsm import xsm as security + for name in security.xmlrpc_exports: + fn = getattr(security, name) + self.server.register_function(fn, "xend.security.%s" % name) + self.server.register_introspection_functions() self.ready = True diff --git a/tools/python/xen/xm/activatepolicy.py b/tools/python/xen/xm/activatepolicy.py deleted file mode 100644 index 270b510eac..0000000000 --- a/tools/python/xen/xm/activatepolicy.py +++ /dev/null @@ -1,111 +0,0 @@ -#============================================================================ -# This library is free software; you can redistribute it and/or -# modify it under the terms of version 2.1 of the GNU Lesser General Public -# License as published by the Free Software Foundation. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#============================================================================ -# Copyright (C) 2007 International Business Machines Corp. -# Author: Stefan Berger -#============================================================================ - -"""Activate the managed policy of the system. -""" - -import sys -from xen.util import xsconstants -from xml.dom import minidom -from xen.xm.opts import OptionError -from xen.xm import getpolicy, setpolicy -from xen.xm import main as xm_main -from xen.xm.main import server - -def help(): - return """ - Usage: xm activatepolicy [options] - - Activate the xend-managed policy. - - The following options are defined: - --load Load the policy into the hypervisor. - --boot Have the system boot with the policy. Changes the default - title in grub.conf. - --noboot Remove the policy from the default entry in grub.conf. - --remove Attempt to remove the current policy by installing the - default policy; this works only if no domains are - running. - """ - -def activate_policy(flags): - policystate = server.xenapi.XSPolicy.get_xspolicy() - xs_ref = policystate['xs_ref'] - if int(policystate['type']) == 0 or xs_ref == "": - print "No policy is installed." - return - rc = int(server.xenapi.XSPolicy.activate_xspolicy(xs_ref, flags)) - if rc == flags: - print "Successfully activated the policy." - else: - print "An error occurred trying to activate the policy: %s" % \ - xsconstants.xserr2string(rc) - -def remove_bootpolicy(): - server.xenapi.XSPolicy.rm_xsbootpolicy() - -def install_default_policy(): - if xm_main.serverType != xm_main.SERVER_XEN_API: - raise OptionError('xm needs to be configured to use the xen-api.') - xs_type = int(server.xenapi.XSPolicy.get_xstype()) - if xs_type & xsconstants.XS_POLICY_ACM == 0: - raise OptionError('ACM policy type not supported on system.') - policystate = server.xenapi.XSPolicy.get_xspolicy() - if int(policystate['type']) == 0: - print 'No policy is installed.' - return - if int(policystate['type']) != xsconstants.XS_POLICY_ACM: - print "Unknown policy type '%s'." % policystate['type'] - flags = int(policystate['flags']) - if flags & xsconstants.XS_INST_LOAD == 0: - print "Default policy is already loaded." - return - setpolicy.setpolicy(xsconstants.ACM_POLICY_ID, 'default', flags, True, - False) - -def main(argv): - if xm_main.serverType != xm_main.SERVER_XEN_API: - raise OptionError('xm needs to be configured to use the xen-api.') - flags = 0 - c = 1 - - while c < len(argv): - if '--boot' == argv[c]: - flags |= xsconstants.XS_INST_BOOT - elif '--load' == argv[c]: - flags |= xsconstants.XS_INST_LOAD - elif '--noboot' == argv[c]: - remove_bootpolicy() - elif '--remove' == argv[c]: - install_default_policy() - return - else: - raise OptionError("Unknown command line option '%s'" % argv[c]) - c += 1 - - if flags != 0: - activate_policy(flags) - - getpolicy.getpolicy(False) - -if __name__ == '__main__': - try: - main(sys.argv) - except Exception, e: - sys.stderr.write('Error: %s\n' % str(e)) - sys.exit(-1) diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py index 0ba3b925ff..fcc3516a51 100644 --- a/tools/python/xen/xm/addlabel.py +++ b/tools/python/xen/xm/addlabel.py @@ -22,7 +22,6 @@ import os import sys -from xen.util import dictio import xen.util.xsm.xsm as security from xen.xm.opts import OptionError from xen.util import xsconstants @@ -37,14 +36,12 @@ def help(): xm addlabel