Add a new attribute to the <seclabel> XML to allow resource relabelling to be enabled with static label usage. <seclabel model='selinux' type='static' relabel='yes'> <label>system_u:system_r:svirt_t:s0:c392,c662</label> </seclabel> * docs/schemas/domain.rng: Add relabel attribute * src/conf/domain_conf.c, src/conf/domain_conf.h: Parse the 'relabel' attribute * src/qemu/qemu_process.c: Unconditionally clear out the 'imagelabel' attribute * src/security/security_apparmor.c: Skip based on 'relabel' attribute instead of label type * src/security/security_selinux.c: Skip based on 'relabel' attribute instead of label type and fill in <imagelabel> attribute if relabel is enabled. --- docs/schemas/domain.rng | 6 ++ src/conf/domain_conf.c | 41 ++++++++-- src/conf/domain_conf.h | 3 +- src/qemu/qemu_process.c | 2 +- src/security/security_apparmor.c | 10 +- src/security/security_selinux.c | 160 ++++++++++++++++++++++++-------------- 6 files changed, 149 insertions(+), 73 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index ab5a56b..fb1497b 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -61,6 +61,12 @@ <value>static</value> </choice> </attribute> + <attribute name="relabel"> + <choice> + <value>yes</value> + <value>no</value> + </choice> + </attribute> <element name="label"> <text/> </element> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index cc318da..dc24d71 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -5072,6 +5072,30 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def, "%s", _("invalid security type")); goto error; } + p = virXPathStringLimit("string(./seclabel/@relabel)", + VIR_SECURITY_LABEL_BUFLEN-1, ctxt); + if (p != NULL) { + if (STREQ(p, "yes")) { + def->seclabel.relabel = true; + } else if (STREQ(p, "no")) { + def->seclabel.relabel = false; + } else { + virDomainReportError(VIR_ERR_XML_ERROR, + _("invalid security relabel value %s"), p); + goto error; + } + if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + !def->seclabel.relabel) { + virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("dynamic label type must use resource relabelling")); + goto error; + } + } else { + if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + def->seclabel.relabel = false; + else + def->seclabel.relabel = true; + } /* Only parse label, if using static labels, or * if the 'live' VM XML is requested @@ -5089,8 +5113,8 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def, def->seclabel.label = p; } - /* Only parse imagelabel, if requested live XML for dynamic label */ - if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + /* Only parse imagelabel, if requested live XML with relabelling */ + if (def->seclabel.relabel && !(flags & VIR_DOMAIN_XML_INACTIVE)) { p = virXPathStringLimit("string(./seclabel/imagelabel[1])", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); @@ -9864,16 +9888,17 @@ char *virDomainDefFormat(virDomainDefPtr def, if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && !def->seclabel.baselabel && (flags & VIR_DOMAIN_XML_INACTIVE)) { - virBufferAsprintf(&buf, " <seclabel type='%s' model='%s'/>\n", - sectype, def->seclabel.model); + virBufferAsprintf(&buf, " <seclabel type='%s' model='%s' relabel='%s'/>\n", + sectype, def->seclabel.model, + def->seclabel.relabel ? "yes" : "no"); } else { - virBufferAsprintf(&buf, " <seclabel type='%s' model='%s'>\n", - sectype, def->seclabel.model); + virBufferAsprintf(&buf, " <seclabel type='%s' model='%s' relabel='%s'>\n", + sectype, def->seclabel.model, + def->seclabel.relabel ? "yes" : "no"); if (def->seclabel.label) virBufferEscapeString(&buf, " <label>%s</label>\n", def->seclabel.label); - if (def->seclabel.imagelabel && - (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)) + if (def->seclabel.relabel && def->seclabel.imagelabel) virBufferEscapeString(&buf, " <imagelabel>%s</imagelabel>\n", def->seclabel.imagelabel); if (def->seclabel.baselabel && diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 17c2584..926f4a9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -959,7 +959,8 @@ struct _virSecurityLabelDef { char *label; /* security label string */ char *imagelabel; /* security image label string */ char *baselabel; /* base name of label string */ - int type; + int type; /* virDomainSeclabelType */ + bool relabel; }; enum virDomainTimerNameType { diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1a404ff..0d547a9 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2911,8 +2911,8 @@ void qemuProcessStop(struct qemud_driver *driver, if (!vm->def->seclabel.baselabel) VIR_FREE(vm->def->seclabel.model); VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); } + VIR_FREE(vm->def->seclabel.imagelabel); virDomainDefClearDeviceAliases(vm->def); if (!priv->persistentAddrs) { diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index b6ce5b7..7c7d0a7 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -265,7 +265,7 @@ reload_profile(virSecurityManagerPtr mgr, int rc = -1; char *profile_name = NULL; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; if ((profile_name = get_profile_name(vm)) == NULL) @@ -461,7 +461,7 @@ static int AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr, virDomainObjPtr vm, const char *stdin_path) { - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) + if (!vm->def->seclabel.relabel) return 0; /* Reload the profile if stdin_path is specified. Note that @@ -610,7 +610,7 @@ AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr, int rc = -1; char *profile_name; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) @@ -682,7 +682,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr, struct SDPDOP *ptr; int ret = -1; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) @@ -741,7 +741,7 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; return reload_profile(mgr, vm, NULL, false); diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 736cd7f..9071ec7 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -165,13 +165,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, virDomainObjPtr vm) { int rc = -1; - char mcs[1024]; + char *mcs = NULL; char *scontext = NULL; int c1 = 0; int c2 = 0; - - if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) - return 0; + context_t ctx = NULL; if ((vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && !vm->def->seclabel.baselabel && @@ -181,13 +179,19 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, return rc; } - if (vm->def->seclabel.label || - vm->def->seclabel.imagelabel) { + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + vm->def->seclabel.label) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("security label already defined for VM")); return rc; } + if (vm->def->seclabel.imagelabel) { + virSecurityReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("security image 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, @@ -196,51 +200,89 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, return rc; } - do { - c1 = virRandom(1024); - c2 = virRandom(1024); - - if ( c1 == c2 ) { - snprintf(mcs, sizeof(mcs), "s0:c%d", c1); - } else { - if ( c1 < c2 ) - snprintf(mcs, sizeof(mcs), "s0:c%d,c%d", c1, c2); - else - snprintf(mcs, sizeof(mcs), "s0:c%d,c%d", c2, c1); + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) { + if (!(ctx = context_new(vm->def->seclabel.label)) ) { + virReportSystemError(errno, + _("unable to allocate socket security context '%s'"), + vm->def->seclabel.label); + return rc; } - } while(mcsAdd(mcs) == -1); - 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); - goto err; + const char *range = context_range_get(ctx); + if (!range || + !(mcs = strdup(range))) { + virReportOOMError(); + goto cleanup; + } + } else { + do { + c1 = virRandom(1024); + c2 = virRandom(1024); + + if ( c1 == c2 ) { + if (virAsprintf(&mcs, "s0:c%d", c1) < 0) { + virReportOOMError(); + goto cleanup; + } + } else { + if (c1 > c2) { + c1 ^= c2; + c2 ^= c1; + c1 ^= c2; + } + if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) { + virReportOOMError(); + goto cleanup; + } + } + } while (mcsAdd(mcs) == -1); + + 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); + goto cleanup; + } } vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs); - if (! vm->def->seclabel.imagelabel) { + if (!vm->def->seclabel.imagelabel) { virSecurityReportError(VIR_ERR_INTERNAL_ERROR, _("cannot generate selinux context for %s"), mcs); - goto err; + goto cleanup; } + if (!vm->def->seclabel.model && !(vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { virReportOOMError(); - goto err; + goto cleanup; } - rc = 0; - goto done; -err: - VIR_FREE(vm->def->seclabel.label); - VIR_FREE(vm->def->seclabel.imagelabel); - if (!vm->def->seclabel.baselabel) - VIR_FREE(vm->def->seclabel.model); -done: + +cleanup: + if (rc != 0) { + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) + VIR_FREE(vm->def->seclabel.label); + VIR_FREE(vm->def->seclabel.imagelabel); + if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && + !vm->def->seclabel.baselabel) + VIR_FREE(vm->def->seclabel.model); + } + + if (ctx) + context_free(ctx); VIR_FREE(scontext); + VIR_FREE(mcs); + + VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s", + NULLSTR(vm->def->seclabel.model), + NULLSTR(vm->def->seclabel.label), + NULLSTR(vm->def->seclabel.imagelabel), + NULLSTR(vm->def->seclabel.baselabel)); + return rc; } @@ -495,7 +537,7 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; /* Don't restore labels on readoly/shared disks, because @@ -579,7 +621,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr, const virSecurityLabelDefPtr secdef = &vm->def->seclabel; bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; return virDomainDiskDefForeachPath(disk, @@ -619,7 +661,7 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int ret = -1; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) @@ -688,7 +730,7 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int ret = -1; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) @@ -742,7 +784,7 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm, char *in = NULL, *out = NULL; int ret = -1; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; switch (dev->type) { @@ -788,7 +830,7 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm, char *in = NULL, *out = NULL; int ret = -1; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; switch (dev->type) { @@ -876,7 +918,7 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, VIR_DEBUG("Restoring security label on %s", vm->def->name); - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; for (i = 0 ; i < vm->def->nhostdevs ; i++) { @@ -922,18 +964,18 @@ SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC || - secdef->label == NULL) - return 0; - - context_t con = context_new(secdef->label); - if (con) { - mcsRemove(context_range_get(con)); - context_free(con); + if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) { + if (secdef->label != NULL) { + context_t con = context_new(secdef->label); + if (con) { + mcsRemove(context_range_get(con)); + context_free(con); + } + } + VIR_FREE(secdef->label); + if (!secdef->baselabel) + VIR_FREE(secdef->model); } - - VIR_FREE(secdef->model); - VIR_FREE(secdef->label); VIR_FREE(secdef->imagelabel); return 0; @@ -947,7 +989,7 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; return SELinuxSetFilecon(savefile, secdef->imagelabel); @@ -961,7 +1003,7 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, { const virSecurityLabelDefPtr secdef = &vm->def->seclabel; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; return SELinuxRestoreSecurityFileLabel(savefile); @@ -1176,7 +1218,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, const virSecurityLabelDefPtr secdef = &vm->def->seclabel; int i; - if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) + if (!secdef->relabel) return 0; for (i = 0 ; i < vm->def->ndisks ; i++) { @@ -1190,6 +1232,8 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, vm, vm->def->disks[i]) < 0) return -1; } + /* XXX fixme process vm->def->fss if relabel == true */ + for (i = 0 ; i < vm->def->nhostdevs ; i++) { if (SELinuxSetSecurityHostdevLabel(mgr, vm, -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list