diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 12a756c281..ec011dd414 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -5029,7 +5029,11 @@ qemu-kvm -net nic,model=? /dev/null a seclabel element is attached to a specific path rather than the top-level domain assignment, only the attribute relabel or the - sub-element label are supported. + sub-element label are supported. Additionally, + since 1.1.2, an output-only + element labelskip will be present for active + domains on disks where labeling was skipped due to the image + being on a file system that lacks security labeling.

Example configs

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index ac807e6caf..dfcd61cdd2 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -152,34 +152,35 @@ + relabel=no or a diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 12b68eadf1..ea49d2cda3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -4484,7 +4484,8 @@ static int virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn, size_t *nseclabels_rtn, virSecurityLabelDefPtr *vmSeclabels, - int nvmSeclabels, xmlXPathContextPtr ctxt) + int nvmSeclabels, xmlXPathContextPtr ctxt, + unsigned int flags) { virSecurityDeviceLabelDefPtr *seclabels; size_t nseclabels = 0; @@ -4492,7 +4493,7 @@ virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn, size_t i, j; xmlNodePtr *list = NULL; virSecurityLabelDefPtr vmDef = NULL; - char *model, *relabel, *label; + char *model, *relabel, *label, *labelskip; if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0) goto error; @@ -4547,6 +4548,13 @@ virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr **seclabels_rtn, seclabels[i]->norelabel = false; } + /* labelskip is only parsed on live images */ + labelskip = virXMLPropString(list[i], "labelskip"); + seclabels[i]->labelskip = false; + if (labelskip && !(flags & VIR_DOMAIN_XML_INACTIVE)) + seclabels[i]->labelskip = STREQ(labelskip, "yes"); + VIR_FREE(labelskip); + ctxt->node = list[i]; label = virXPathStringLimit("string(./label)", VIR_SECURITY_LABEL_BUFLEN-1, ctxt); @@ -5208,7 +5216,8 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt, &def->nseclabels, vmSeclabels, nvmSeclabels, - ctxt) < 0) + ctxt, + flags) < 0) goto error; ctxt->node = saved_node; } @@ -6884,7 +6893,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, &chr_def->nseclabels, vmSeclabels, nvmSeclabels, - ctxt) < 0) { + ctxt, + flags) < 0) { ctxt->node = saved_node; goto error; } @@ -14018,14 +14028,23 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def) static void virSecurityDeviceLabelDefFormat(virBufferPtr buf, - virSecurityDeviceLabelDefPtr def) + virSecurityDeviceLabelDefPtr def, + unsigned int flags) { + /* For offline output, skip elements that allow labels but have no + * label specified (possible if labelskip was ignored on input). */ + if ((flags & VIR_DOMAIN_XML_INACTIVE) && !def->label && !def->norelabel) + return; + virBufferAddLit(buf, "model) virBufferAsprintf(buf, " model='%s'", def->model); - virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes"); + if (def->labelskip) + virBufferAddLit(buf, " labelskip='yes'"); + else + virBufferAsprintf(buf, " relabel='%s'", def->norelabel ? "no" : "yes"); if (def->label) { virBufferAddLit(buf, ">\n"); @@ -14100,7 +14119,8 @@ virDomainDiskBlockIoDefFormat(virBufferPtr buf, static int virDomainDiskSourceDefFormat(virBufferPtr buf, - virDomainDiskDefPtr def) + virDomainDiskDefPtr def, + unsigned int flags) { int n; const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy); @@ -14119,7 +14139,8 @@ virDomainDiskSourceDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); for (n = 0; n < def->nseclabels; n++) - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n], + flags); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " \n"); } else { @@ -14136,7 +14157,8 @@ virDomainDiskSourceDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); for (n = 0; n < def->nseclabels; n++) - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n], + flags); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " \n"); } else { @@ -14201,7 +14223,8 @@ virDomainDiskSourceDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); virBufferAdjustIndent(buf, 8); for (n = 0; n < def->nseclabels; n++) - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n], + flags); virBufferAdjustIndent(buf, -8); virBufferAddLit(buf, " \n"); } else { @@ -14337,7 +14360,7 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAddLit(buf, " \n"); } - if (virDomainDiskSourceDefFormat(buf, def) < 0) + if (virDomainDiskSourceDefFormat(buf, def, flags) < 0) return -1; virDomainDiskGeometryDefFormat(buf, def); virDomainDiskBlockIoDefFormat(buf, def); @@ -15189,7 +15212,7 @@ virDomainChrDefFormat(virBufferPtr buf, if (def->seclabels && def->nseclabels > 0) { virBufferAdjustIndent(buf, 2); for (n = 0; n < def->nseclabels; n++) - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n], flags); virBufferAdjustIndent(buf, -2); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3e118d63d3..500a5be9d8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -343,7 +343,8 @@ typedef virSecurityDeviceLabelDef *virSecurityDeviceLabelDefPtr; struct _virSecurityDeviceLabelDef { char *model; char *label; /* image label string */ - bool norelabel; + bool norelabel; /* true to skip label attempts */ + bool labelskip; /* live-only; true if skipping failed label attempt */ }; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index e3dce66a2d..38de06076b 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -917,10 +917,10 @@ virSecuritySELinuxSetFileconHelper(const char *path, char *tcon, bool optional) security_get_boolean_active("virt_use_nfs") != 1) { msg = _("Setting security context '%s' on '%s' not supported. " "Consider setting virt_use_nfs"); - if (security_getenforce() == 1) - VIR_WARN(msg, tcon, path); - else - VIR_INFO(msg, tcon, path); + if (security_getenforce() == 1) + VIR_WARN(msg, tcon, path); + else + VIR_INFO(msg, tcon, path); } else { VIR_INFO("Setting security context '%s' on '%s' not supported", tcon, path); @@ -1135,6 +1135,14 @@ virSecuritySELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr, if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel)) return 0; + /* If labelskip is true and there are no backing files, then we + * know it is safe to skip the restore. FIXME - backing files should + * be tracked in domain XML, at which point labelskip should be a + * per-file attribute instead of a disk attribute. */ + if (disk_seclabel && disk_seclabel->labelskip && + !disk->backingChain) + return 0; + /* Don't restore labels on readoly/shared disks, because * other VMs may still be accessing these * Alternatively we could iterate over all running @@ -1219,7 +1227,7 @@ virSecuritySELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk, disk_seclabel = virDomainDiskDefGenSecurityLabelDef(SECURITY_SELINUX_NAME); if (!disk_seclabel) return -1; - disk_seclabel->norelabel = true; + disk_seclabel->labelskip = true; if (VIR_APPEND_ELEMENT(disk->seclabels, disk->nseclabels, disk_seclabel) < 0) { virSecurityDeviceLabelDefFree(disk_seclabel); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.args b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.args new file mode 100644 index 0000000000..892c6b5830 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.args @@ -0,0 +1,5 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \ +-name QEMUGuest1 -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \ +-hda /dev/HostVG/QEMUGuest1 \ +-net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.xml b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.xml new file mode 100644 index 0000000000..e3bc7009d9 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-labelskip.xml @@ -0,0 +1,32 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + +
+ + + + + + + + system_u:system_r:svirt_custom_t:s0 + + diff --git a/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.args b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.args new file mode 100644 index 0000000000..892c6b5830 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.args @@ -0,0 +1,5 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \ +-name QEMUGuest1 -S -M pc -m 214 -smp 1 -nographic -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \ +-hda /dev/HostVG/QEMUGuest1 \ +-net none -serial none -parallel none diff --git a/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.xml b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.xml new file mode 100644 index 0000000000..a7434481db --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-seclabel-static-labelskip.xml @@ -0,0 +1,33 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + + +
+ + + + + + + + + system_u:system_r:svirt_custom_t:s0:c192,c392 + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 679124e35b..3a3c304157 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -923,8 +923,10 @@ mymain(void) DO_TEST("seclabel-dynamic", QEMU_CAPS_NAME); DO_TEST("seclabel-dynamic-baselabel", QEMU_CAPS_NAME); DO_TEST("seclabel-dynamic-override", QEMU_CAPS_NAME); + DO_TEST("seclabel-dynamic-labelskip", QEMU_CAPS_NAME); DO_TEST("seclabel-static", QEMU_CAPS_NAME); DO_TEST("seclabel-static-relabel", QEMU_CAPS_NAME); + DO_TEST("seclabel-static-labelskip", QEMU_CAPS_NAME); DO_TEST("seclabel-none", QEMU_CAPS_NAME); DO_TEST("pseries-basic", diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-seclabel-dynamic-labelskip.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-seclabel-dynamic-labelskip.xml new file mode 100644 index 0000000000..07646913d6 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-seclabel-dynamic-labelskip.xml @@ -0,0 +1,31 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + +
+ + + + + + + + system_u:system_r:svirt_custom_t:s0 + + diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 5c6730d25e..6eebc685f9 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -30,6 +30,7 @@ testCompareXMLToXMLFiles(const char *inxml, const char *outxml, bool live) char *actual = NULL; int ret = -1; virDomainDefPtr def = NULL; + unsigned int flags = live ? 0 : VIR_DOMAIN_XML_INACTIVE; if (virtTestLoadFile(inxml, &inXmlData) < 0) goto fail; @@ -37,11 +38,10 @@ testCompareXMLToXMLFiles(const char *inxml, const char *outxml, bool live) goto fail; if (!(def = virDomainDefParseString(inXmlData, driver.caps, driver.xmlopt, - QEMU_EXPECTED_VIRT_TYPES, - live ? 0 : VIR_DOMAIN_XML_INACTIVE))) + QEMU_EXPECTED_VIRT_TYPES, flags))) goto fail; - if (!(actual = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE))) + if (!(actual = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE | flags))) goto fail; if (STRNEQ(outXmlData, actual)) { @@ -257,7 +257,9 @@ mymain(void) DO_TEST_FULL("seclabel-dynamic-baselabel", false, WHEN_INACTIVE); DO_TEST_FULL("seclabel-dynamic-override", false, WHEN_INACTIVE); + DO_TEST_FULL("seclabel-dynamic-labelskip", true, WHEN_INACTIVE); DO_TEST("seclabel-static"); + DO_TEST_FULL("seclabel-static-labelskip", false, WHEN_ACTIVE); DO_TEST("seclabel-none"); DO_TEST("numad-static-vcpu-no-numatune"); DO_TEST("disk-scsi-lun-passthrough-sgio");