diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 891662df7c..ab5a56b218 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -67,6 +67,9 @@ + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f9bf51e3c7..1da242fd16 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -966,6 +966,7 @@ void virSecurityLabelDefFree(virDomainDefPtr def) VIR_FREE(def->seclabel.model); VIR_FREE(def->seclabel.label); VIR_FREE(def->seclabel.imagelabel); + VIR_FREE(def->seclabel.baselabel); } static void @@ -5072,20 +5073,11 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def, goto error; } - /* Only parse details, if using static labels, or + /* Only parse label, if using static labels, or * if the 'live' VM XML is requested */ if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC || !(flags & VIR_DOMAIN_XML_INACTIVE)) { - p = virXPathStringLimit("string(./seclabel/@model)", - VIR_SECURITY_MODEL_BUFLEN-1, ctxt); - if (p == NULL) { - virDomainReportError(VIR_ERR_XML_ERROR, - "%s", _("missing security model")); - goto error; - } - def->seclabel.model = p; - p = virXPathStringLimit("string(./seclabel/label[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (p == NULL) { @@ -5110,6 +5102,30 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def, def->seclabel.imagelabel = p; } + /* Only parse baselabel, for dynamic label */ + if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + p = virXPathStringLimit("string(./seclabel/baselabel[1])", + VIR_SECURITY_LABEL_BUFLEN-1, ctxt); + if (p != NULL) + def->seclabel.baselabel = p; + } + + /* Only parse model, if static labelling, or a base + * label is set, or doing active XML + */ + if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC || + def->seclabel.baselabel || + !(flags & VIR_DOMAIN_XML_INACTIVE)) { + p = virXPathStringLimit("string(./seclabel/@model)", + VIR_SECURITY_MODEL_BUFLEN-1, ctxt); + if (p == NULL) { + virDomainReportError(VIR_ERR_XML_ERROR, + "%s", _("missing security model")); + goto error; + } + def->seclabel.model = p; + } + return 0; error: @@ -9844,20 +9860,26 @@ char *virDomainDefFormat(virDomainDefPtr def, const char *sectype = virDomainSeclabelTypeToString(def->seclabel.type); if (!sectype) goto cleanup; - if (!def->seclabel.label || - (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && - (flags & VIR_DOMAIN_XML_INACTIVE))) { + + if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + !def->seclabel.baselabel && + (flags & VIR_DOMAIN_XML_INACTIVE)) { virBufferAsprintf(&buf, " \n", sectype, def->seclabel.model); } else { virBufferAsprintf(&buf, " \n", - sectype, def->seclabel.model); - virBufferEscapeString(&buf, " \n", - def->seclabel.label); + sectype, def->seclabel.model); + if (def->seclabel.label) + virBufferEscapeString(&buf, " \n", + def->seclabel.label); if (def->seclabel.imagelabel && - def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) + (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)) virBufferEscapeString(&buf, " %s\n", def->seclabel.imagelabel); + if (def->seclabel.baselabel && + (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)) + virBufferEscapeString(&buf, " %s\n", + def->seclabel.baselabel); virBufferAddLit(&buf, " \n"); } } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e81977c61a..76b9ca7395 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -958,6 +958,7 @@ struct _virSecurityLabelDef { char *model; /* name of security model */ char *label; /* security label string */ char *imagelabel; /* security image label string */ + char *baselabel; /* base name of label string */ int type; }; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 88a31a3e54..69788dfa1c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2883,7 +2883,8 @@ void qemuProcessStop(struct qemud_driver *driver, /* Clear out dynamically assigned labels */ if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) { - VIR_FREE(vm->def->seclabel.model); + if (!vm->def->seclabel.baselabel) + VIR_FREE(vm->def->seclabel.model); VIR_FREE(vm->def->seclabel.label); VIR_FREE(vm->def->seclabel.imagelabel); } diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index 6795184c4c..bbdcbf023c 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -398,6 +398,12 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) return 0; + if (vm->def->seclabel.baselabel) { + virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("Cannot set a base label with AppArmour")); + return rc; + } + if ((vm->def->seclabel.label) || (vm->def->seclabel.model) || (vm->def->seclabel.imagelabel)) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index a022daa778..913c7a622d 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -173,14 +173,29 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) return 0; + if ((vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && + !vm->def->seclabel.baselabel && + vm->def->seclabel.model) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("security model already defined for VM")); + return rc; + } + if (vm->def->seclabel.label || - vm->def->seclabel.model || vm->def->seclabel.imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); return rc; } + if (vm->def->seclabel.model && + STRNEQ(vm->def->seclabel.model, SECURITY_SELINUX_NAME)) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + _("security label model %s is not supported with selinux"), + vm->def->seclabel.model); + return rc; + } + do { c1 = virRandom(1024); c2 = virRandom(1024); @@ -195,7 +210,10 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, } } while(mcsAdd(mcs) == -1); - vm->def->seclabel.label = SELinuxGenNewContext(default_domain_context, mcs); + vm->def->seclabel.label = + SELinuxGenNewContext(vm->def->seclabel.baselabel ? + vm->def->seclabel.baselabel : + default_domain_context, mcs); if (! vm->def->seclabel.label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); @@ -207,8 +225,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, _("cannot generate selinux context for %s"), mcs); goto err; } - vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME); - if (!vm->def->seclabel.model) { + if (!vm->def->seclabel.model && + !(vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { virReportOOMError(); goto err; } @@ -219,7 +237,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, err: VIR_FREE(vm->def->seclabel.label); VIR_FREE(vm->def->seclabel.imagelabel); - VIR_FREE(vm->def->seclabel.model); + if (!vm->def->seclabel.baselabel) + VIR_FREE(vm->def->seclabel.model); done: VIR_FREE(scontext); return rc;