[libvirt] [PATCH 0/3] Improve flexibility of SELinux labelling

This patch series adds two new features - The ability to override 'system_u:system_r:svirt_t:s0' from /etc/selinux/targeted/contexts/virtual_domain_context using the guest XML - The ability to use dynamic relabelling of resources, in combo with static VM label assignment. The latter is useful for management applications which want to be in full control of assigning VM labels (so that they can be unique across an entire cluster of hosts for example), while still benefiting from automatic relabelling of resources in the XML.

Normally the dynamic labelling mode will always use a base label of 'svirt_t' for VMs. Introduce a <baselabel> field in the <seclabel> XML to allow this base label to be changed eg <seclabel type='dynamic' model='selinux'> <baselabel>system_u:object_r:virt_t:s0</baselabel> </seclabel> * docs/schemas/domain.rng: Add <baselabel> * src/conf/domain_conf.c, src/conf/domain_conf.h: Parsing of base label * src/qemu/qemu_process.c: Don't reset 'model' attribute if a base label is specified * src/security/security_apparmor.c: Refuse to support base label * src/security/security_selinux.c: Use 'baselabel' when generating label, if available --- docs/schemas/domain.rng | 3 ++ src/conf/domain_conf.c | 56 ++++++++++++++++++++++++++----------- src/conf/domain_conf.h | 1 + src/qemu/qemu_process.c | 3 +- src/security/security_apparmor.c | 6 ++++ src/security/security_selinux.c | 29 ++++++++++++++++--- 6 files changed, 75 insertions(+), 23 deletions(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index 891662d..ab5a56b 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -67,6 +67,9 @@ <element name="imagelabel"> <text/> </element> + <element name="baselabel"> + <text/> + </element> </element> </define> <define name="hvs"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3d290fb..cc318da 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, " <seclabel type='%s' model='%s'/>\n", sectype, def->seclabel.model); } else { virBufferAsprintf(&buf, " <seclabel type='%s' model='%s'>\n", - sectype, def->seclabel.model); - virBufferEscapeString(&buf, " <label>%s</label>\n", - def->seclabel.label); + sectype, def->seclabel.model); + if (def->seclabel.label) + virBufferEscapeString(&buf, " <label>%s</label>\n", + def->seclabel.label); if (def->seclabel.imagelabel && - def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) + (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)) virBufferEscapeString(&buf, " <imagelabel>%s</imagelabel>\n", def->seclabel.imagelabel); + if (def->seclabel.baselabel && + (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)) + virBufferEscapeString(&buf, " <baselabel>%s</baselabel>\n", + def->seclabel.baselabel); virBufferAddLit(&buf, " </seclabel>\n"); } } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index aa25e36..17c2584 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 bb83be0..1a404ff 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2908,7 +2908,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 aebf44e..b6ce5b7 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 0ce999f..736cd7f 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; -- 1.7.4.4

On 06/27/2011 06:20 AM, Daniel P. Berrange wrote:
Normally the dynamic labelling mode will always use a base label of 'svirt_t' for VMs. Introduce a <baselabel> field in the <seclabel> XML to allow this base label to be changed
eg
<seclabel type='dynamic' model='selinux'> <baselabel>system_u:object_r:virt_t:s0</baselabel> </seclabel>
* docs/schemas/domain.rng: Add <baselabel> * src/conf/domain_conf.c, src/conf/domain_conf.h: Parsing of base label * src/qemu/qemu_process.c: Don't reset 'model' attribute if a base label is specified * src/security/security_apparmor.c: Refuse to support base label * src/security/security_selinux.c: Use 'baselabel' when generating label, if available
The code looks okay, but this missed the RC1 freeze. Is this something we need in 0.9.3 for a bug-fix, or should it wait until after the release as a feature addition?
--- docs/schemas/domain.rng | 3 ++
Missing the counterpart to docs/formatdomain.html.in. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

On Mon, Jun 27, 2011 at 10:07:23AM -0600, Eric Blake wrote:
On 06/27/2011 06:20 AM, Daniel P. Berrange wrote:
Normally the dynamic labelling mode will always use a base label of 'svirt_t' for VMs. Introduce a <baselabel> field in the <seclabel> XML to allow this base label to be changed
eg
<seclabel type='dynamic' model='selinux'> <baselabel>system_u:object_r:virt_t:s0</baselabel> </seclabel>
* docs/schemas/domain.rng: Add <baselabel> * src/conf/domain_conf.c, src/conf/domain_conf.h: Parsing of base label * src/qemu/qemu_process.c: Don't reset 'model' attribute if a base label is specified * src/security/security_apparmor.c: Refuse to support base label * src/security/security_selinux.c: Use 'baselabel' when generating label, if available
The code looks okay, but this missed the RC1 freeze. Is this something we need in 0.9.3 for a bug-fix, or should it wait until after the release as a feature addition?
It isn't critical for 0.9.3, and I have more SELinux additions pending, so I'll wait until after 0.9.3 Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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

On 06/27/2011 06:20 AM, Daniel P. Berrange wrote:
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
Missing docs/formatdomain.html.in counterpart.
+++ 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"));
s/relabelling/relabeling/ since user-visible messages should prefer US spelling (double-l is UK spelling). A proper en_UK locale .po file would then get the UK spelling (do we have one of those?). -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

The domain XML documentation is missing information about the <seclabel> element used by security drivers * formatdomain.html.in: Document <seclabel> --- docs/formatdomain.html.in | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3a64983..c1ea480 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2614,6 +2614,82 @@ qemu-kvm -net nic,model=? /dev/null </dd> </dl> + <h3><a name="seclabel">Security label</a></h3> + + <p> + The <code>seclabel</code> element allows control over the + operation of the security drivers. There are two basic + modes of operation, dynamic where libvirt automatically + generates a unique security label, or static where the + application/administrator chooses the labels. With dynamic + label generation, libvirt will always automatically + relabel any resources associated with the virtual machine. + With static label assignment, by default, the administrator + or application must ensure labels are set correctly on any + resources, however, automatic relabelling can be enabled + if desired + </p> + + <p> + Valid input XML configurations for the security label + are: + </p> + + <pre> + <seclabel type='dynamic' model='selinux'/> + + <seclabel type='dynamic' model='selinux'> + <baselabel>system_u:system_r:my_svirt_t:s0</baselabel> + </seclabel> + + <seclabel type='static' model='selinux' relabel='no'> + <label>system_u:system_r:svirt_t:s0:c392,c662</label> + </seclabel> + + <seclabel type='static' model='selinux' relabel='yes'> + <label>system_u:system_r:svirt_t:s0:c392,c662</label> + </seclabel> + </pre> + + <p> + When viewing the XML for a running guest with automatic + resource relabelling active, an additional XML element, + <code>imagelabel</code>, will be included. This is an + output-only element, so will be ignored in user supplied + XML documents + </p> + <dl> + <dt><code>type</code></dt> + <dd>Either <code>static</code> or <code>dynamic</code> to determine + whether libvirt automatically generates a unique security label + or not. + </dd> + <dt><code>model</code></dt> + <dd>A valid security model name, matching the currently + activated security model + </dd> + <dt><code>relabel</code></dt> + <dd>Either <code>yes</code> or <code>no</code>. This must always + be <code>yes</code> if dynamic label assignment is used. With + static label assignment it will default to <code>no</code>. + </dd> + <dt><code>label</code></dt> + <dd>If static labelling is used, this must specify the full + security label to assign to the virtual domain. The format + of the content depends on the security driver in use + </dd> + <dt><code>baselabel</code></dt> + <dd>If dynamic labelling is used, this can optionally be + used to specify the base security label. The format + of the content depends on the security driver in use + </dd> + <dt><code>imagelabel</code></dt> + <dd>This is an output only element, which shows the + security label used on resources associated with the virtual domain. + The format of the content depends on the security driver in use + </dd> + </dl> + <h2><a name="examples">Example configs</a></h2> <p> -- 1.7.4.4

On 06/27/2011 06:20 AM, Daniel P. Berrange wrote:
The domain XML documentation is missing information about the <seclabel> element used by security drivers
* formatdomain.html.in: Document <seclabel> --- docs/formatdomain.html.in | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0 deletions(-)
Oh, this covers part of my complaint in both 1/3 and 2/3. If we decide to defer those patches until post-0.9.3, then there is still a good chunk of this patch which should be applied now.
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3a64983..c1ea480 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2614,6 +2614,82 @@ qemu-kvm -net nic,model=? /dev/null </dd> </dl>
+ <h3><a name="seclabel">Security label</a></h3> + + <p> + The <code>seclabel</code> element allows control over the + operation of the security drivers. There are two basic + modes of operation, dynamic where libvirt automatically + generates a unique security label, or static where the + application/administrator chooses the labels. With dynamic + label generation, libvirt will always automatically + relabel any resources associated with the virtual machine. + With static label assignment, by default, the administrator + or application must ensure labels are set correctly on any + resources, however, automatic relabelling can be enabled
s/relabelling/relabeling/ if we are going to favor US spellings in public-facing documentation
+ if desired + </p> + + <p> + Valid input XML configurations for the security label + are: + </p> + + <pre> + <seclabel type='dynamic' model='selinux'/> + + <seclabel type='dynamic' model='selinux'> + <baselabel>system_u:system_r:my_svirt_t:s0</baselabel> + </seclabel>
For example, up to here is useful to be applied now...
+ + <seclabel type='static' model='selinux' relabel='no'> + <label>system_u:system_r:svirt_t:s0:c392,c662</label> + </seclabel>
...while this depends on the rest of the series. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 06/27/2011 08:20 AM, Daniel P. Berrange wrote:
This patch series adds two new features
- The ability to override 'system_u:system_r:svirt_t:s0' from /etc/selinux/targeted/contexts/virtual_domain_context using the guest XML - The ability to use dynamic relabelling of resources, in combo with static VM label assignment.
The latter is useful for management applications which want to be in full control of assigning VM labels (so that they can be unique across an entire cluster of hosts for example), while still benefiting from automatic relabelling of resources in the XML.
I think you might want to be a little more flexible with this. I see where you would want 4 ways of doing this. Dynamic with /etc/selinux/targeted/contexts/virtual_domain_context Dynamic with alternate TYPE, Meaning I could specify system_u:system_r:svirt_apache_t:s0 and then libvirt would select a MCS label for this context and launch system_u:system_r:svirt_apache_t:s0:c1,c257 Static with no relabel. Static with relabel. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAk4JuxgACgkQrlYvE4MpobMIyACeMEHG5Iv2fP15pexyss34wsGF dGsAn1gKtRuMeuVKBdU4TJL6Ar1Kl1ZB =V6qL -----END PGP SIGNATURE-----

On Tue, Jun 28, 2011 at 07:29:28AM -0400, Daniel J Walsh wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 06/27/2011 08:20 AM, Daniel P. Berrange wrote:
This patch series adds two new features
- The ability to override 'system_u:system_r:svirt_t:s0' from /etc/selinux/targeted/contexts/virtual_domain_context using the guest XML - The ability to use dynamic relabelling of resources, in combo with static VM label assignment.
The latter is useful for management applications which want to be in full control of assigning VM labels (so that they can be unique across an entire cluster of hosts for example), while still benefiting from automatic relabelling of resources in the XML.
I think you might want to be a little more flexible with this. I see where you would want 4 ways of doing this.
We already do options 1 and 3. These two patches I post let us also support options 2 and 4, so I think we're sorted.
Dynamic with /etc/selinux/targeted/contexts/virtual_domain_context
<seclabel type='dynamic'/>
Dynamic with alternate TYPE, Meaning I could specify system_u:system_r:svirt_apache_t:s0 and then libvirt would select a MCS label for this context and launch system_u:system_r:svirt_apache_t:s0:c1,c257
<seclabel type='dynamic'> <baselabel>system_u:system_r:svirt_apache_t:s0</baselabel> </seclabel>
Static with no relabel.
<seclabel type='static' relabel='no'> <label>system_u:system_r:svirt_apache_t:s0:c1,c257</label> </seclabel>
Static with relabel.
<seclabel type='static' relabel='yes'> <label>system_u:system_r:svirt_apache_t:s0:c1,c257</label> </seclabel> Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 06/28/2011 08:23 AM, Daniel P. Berrange wrote:
On Tue, Jun 28, 2011 at 07:29:28AM -0400, Daniel J Walsh wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 06/27/2011 08:20 AM, Daniel P. Berrange wrote:
This patch series adds two new features
- The ability to override 'system_u:system_r:svirt_t:s0' from /etc/selinux/targeted/contexts/virtual_domain_context using the guest XML - The ability to use dynamic relabelling of resources, in combo with static VM label assignment.
The latter is useful for management applications which want to be in full control of assigning VM labels (so that they can be unique across an entire cluster of hosts for example), while still benefiting from automatic relabelling of resources in the XML.
I think you might want to be a little more flexible with this. I see where you would want 4 ways of doing this.
We already do options 1 and 3. These two patches I post let us also support options 2 and 4, so I think we're sorted.
Dynamic with /etc/selinux/targeted/contexts/virtual_domain_context
<seclabel type='dynamic'/>
Dynamic with alternate TYPE, Meaning I could specify system_u:system_r:svirt_apache_t:s0 and then libvirt would select a MCS label for this context and launch system_u:system_r:svirt_apache_t:s0:c1,c257
<seclabel type='dynamic'> <baselabel>system_u:system_r:svirt_apache_t:s0</baselabel> </seclabel>
Static with no relabel.
<seclabel type='static' relabel='no'> <label>system_u:system_r:svirt_apache_t:s0:c1,c257</label> </seclabel>
Static with relabel.
<seclabel type='static' relabel='yes'> <label>system_u:system_r:svirt_apache_t:s0:c1,c257</label> </seclabel>
Regards, Daniel Great thanks. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
iEYEARECAAYFAk4JzzMACgkQrlYvE4MpobOlQQCgl14dE0FPEWwNUW+YdsF6dV4w w8oAoJLvSuGlJuc6T7avEUyz1JyzfnG9 =QKcR -----END PGP SIGNATURE-----
participants (3)
-
Daniel J Walsh
-
Daniel P. Berrange
-
Eric Blake