提交 b4343293 编写于 作者: E Eric Blake 提交者: Daniel Veillard

seclabel: allow a seclabel override on a disk src

Implement the parsing and formatting of the XML addition of
the previous commit.  The new XML doesn't affect qemu command
line, so we can now test round-trip XML->memory->XML handling.

I chose to reuse the existing structure, even though per-device
override doesn't use all of those fields, rather than create a
new structure, in order to reuse more code.

* src/conf/domain_conf.h (_virDomainDiskDef): Add seclabel member.
* src/conf/domain_conf.c (virDomainDiskDefFree): Free it.
(virSecurityLabelDefFree): New function.
(virDomainDiskDefFormat): Print it.
(virSecurityLabelDefFormat): Reduce output if model not present.
(virDomainDiskDefParseXML): Alter signature, and parse seclabel.
(virSecurityLabelDefParseXML): Split...
(virSecurityLabelDefParseXMLHelper): ...into new helper.
(virDomainDeviceDefParse, virDomainDefParseXML): Update callers.
* tests/qemuxml2argvdata/qemuxml2argv-seclabel-dynamic-override.args:
New file.
* tests/qemuxml2xmltest.c (mymain): Enhance test.
* tests/qemuxml2argvtest.c (mymain): Likewise.
上级 6cb4acce
...@@ -797,6 +797,15 @@ virSecurityLabelDefClear(virSecurityLabelDefPtr def) ...@@ -797,6 +797,15 @@ virSecurityLabelDefClear(virSecurityLabelDefPtr def)
VIR_FREE(def->baselabel); VIR_FREE(def->baselabel);
} }
static void
virSecurityLabelDefFree(virSecurityLabelDefPtr def)
{
if (!def)
return;
virSecurityLabelDefClear(def);
VIR_FREE(def);
}
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def) void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
{ {
int ii; int ii;
...@@ -866,6 +875,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) ...@@ -866,6 +875,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
VIR_FREE(def->serial); VIR_FREE(def->serial);
VIR_FREE(def->src); VIR_FREE(def->src);
virSecurityLabelDefFree(def->seclabel);
VIR_FREE(def->dst); VIR_FREE(def->dst);
VIR_FREE(def->driverName); VIR_FREE(def->driverName);
VIR_FREE(def->driverType); VIR_FREE(def->driverType);
...@@ -2517,31 +2527,32 @@ virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def) ...@@ -2517,31 +2527,32 @@ virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def)
return 0; return 0;
} }
/* Parse the portion of a SecurityLabel that is common to both the
* top-level <seclabel> and to a per-device override.
* default_seclabel is NULL for top-level, or points to the top-level
* when parsing an override. */
static int static int
virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, virSecurityLabelDefParseXMLHelper(virSecurityLabelDefPtr def,
xmlXPathContextPtr ctxt, xmlNodePtr node,
unsigned int flags) xmlXPathContextPtr ctxt,
virSecurityLabelDefPtr default_seclabel,
unsigned int flags)
{ {
char *p; char *p;
xmlNodePtr save_ctxt = ctxt->node;
int ret = -1;
if (virXPathNode("./seclabel", ctxt) == NULL) ctxt->node = node;
return 0;
p = virXPathStringLimit("string(./seclabel/@type)", /* Can't use overrides if top-level doesn't allow relabeling. */
VIR_SECURITY_LABEL_BUFLEN-1, ctxt); if (default_seclabel && default_seclabel->norelabel) {
if (p == NULL) { virDomainReportError(VIR_ERR_XML_ERROR, "%s",
virDomainReportError(VIR_ERR_XML_ERROR, _("label overrides require relabeling to be "
"%s", _("missing security type")); "enabled at the domain level"));
goto error; goto cleanup;
}
def->type = virDomainSeclabelTypeFromString(p);
VIR_FREE(p);
if (def->type < 0) {
virDomainReportError(VIR_ERR_XML_ERROR,
"%s", _("invalid security type"));
goto error;
} }
p = virXPathStringLimit("string(./seclabel/@relabel)",
p = virXPathStringLimit("string(./@relabel)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt); VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p != NULL) { if (p != NULL) {
if (STREQ(p, "yes")) { if (STREQ(p, "yes")) {
...@@ -2552,38 +2563,76 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def, ...@@ -2552,38 +2563,76 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
virDomainReportError(VIR_ERR_XML_ERROR, virDomainReportError(VIR_ERR_XML_ERROR,
_("invalid security relabel value %s"), p); _("invalid security relabel value %s"), p);
VIR_FREE(p); VIR_FREE(p);
goto error; goto cleanup;
} }
VIR_FREE(p); VIR_FREE(p);
if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC && if (!default_seclabel &&
def->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
def->norelabel) { def->norelabel) {
virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED, virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
"%s", _("dynamic label type must use resource relabeling")); "%s", _("dynamic label type must use resource relabeling"));
goto error; goto cleanup;
} }
} else { } else {
if (def->type == VIR_DOMAIN_SECLABEL_STATIC) if (!default_seclabel && def->type == VIR_DOMAIN_SECLABEL_STATIC)
def->norelabel = true; def->norelabel = true;
else else
def->norelabel = false; def->norelabel = false;
} }
/* Only parse label, if using static labels, or /* Only parse label, if using static labels, or
* if the 'live' VM XML is requested * if the 'live' VM XML is requested, or if this is a device override
*/ */
if (def->type == VIR_DOMAIN_SECLABEL_STATIC || if (def->type == VIR_DOMAIN_SECLABEL_STATIC ||
!(flags & VIR_DOMAIN_XML_INACTIVE)) { !(flags & VIR_DOMAIN_XML_INACTIVE) ||
p = virXPathStringLimit("string(./seclabel/label[1])", (default_seclabel && !def->norelabel)) {
p = virXPathStringLimit("string(./label[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt); VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p == NULL) { if (p == NULL) {
virDomainReportError(VIR_ERR_XML_ERROR, virDomainReportError(VIR_ERR_XML_ERROR,
"%s", _("security label is missing")); "%s", _("security label is missing"));
goto error; goto cleanup;
} }
def->label = p; def->label = p;
} }
ret = 0;
cleanup:
ctxt->node = save_ctxt;
return ret;
}
/* Parse the top-level <seclabel>, if present. */
static int
virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
xmlXPathContextPtr ctxt,
unsigned int flags)
{
char *p;
xmlNodePtr node = virXPathNode("./seclabel", ctxt);
if (node == NULL)
return 0;
p = virXPathStringLimit("string(./seclabel/@type)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p == NULL) {
virDomainReportError(VIR_ERR_XML_ERROR,
"%s", _("missing security type"));
goto error;
}
def->type = virDomainSeclabelTypeFromString(p);
VIR_FREE(p);
if (def->type < 0) {
virDomainReportError(VIR_ERR_XML_ERROR,
"%s", _("invalid security type"));
goto error;
}
if (virSecurityLabelDefParseXMLHelper(def, node, ctxt, NULL, flags) < 0)
goto error;
/* Only parse imagelabel, if requested live XML with relabeling */ /* Only parse imagelabel, if requested live XML with relabeling */
if (!def->norelabel && if (!def->norelabel &&
!(flags & VIR_DOMAIN_XML_INACTIVE)) { !(flags & VIR_DOMAIN_XML_INACTIVE)) {
...@@ -2709,6 +2758,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, ...@@ -2709,6 +2758,7 @@ virDomainDiskDefParseXML(virCapsPtr caps,
xmlNodePtr node, xmlNodePtr node,
xmlXPathContextPtr ctxt, xmlXPathContextPtr ctxt,
virBitmapPtr bootMap, virBitmapPtr bootMap,
virSecurityLabelDefPtr default_seclabel,
unsigned int flags) unsigned int flags)
{ {
virDomainDiskDefPtr def; virDomainDiskDefPtr def;
...@@ -3016,6 +3066,16 @@ virDomainDiskDefParseXML(virCapsPtr caps, ...@@ -3016,6 +3066,16 @@ virDomainDiskDefParseXML(virCapsPtr caps,
goto error; goto error;
} }
/* If source is present, check for an optional seclabel override. */
if (source) {
xmlNodePtr seclabel = virXPathNode("./source/seclabel", ctxt);
if (seclabel &&
(VIR_ALLOC(def->seclabel) < 0 ||
virSecurityLabelDefParseXMLHelper(def->seclabel, seclabel, ctxt,
default_seclabel, flags) < 0))
goto error;
}
if (target == NULL) { if (target == NULL) {
virDomainReportError(VIR_ERR_NO_TARGET, virDomainReportError(VIR_ERR_NO_TARGET,
source ? "%s" : NULL, source); source ? "%s" : NULL, source);
...@@ -6344,7 +6404,8 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, ...@@ -6344,7 +6404,8 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
if (xmlStrEqual(node->name, BAD_CAST "disk")) { if (xmlStrEqual(node->name, BAD_CAST "disk")) {
dev->type = VIR_DOMAIN_DEVICE_DISK; dev->type = VIR_DOMAIN_DEVICE_DISK;
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt, if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt,
NULL, flags))) NULL, &def->seclabel,
flags)))
goto error; goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "lease")) { } else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
dev->type = VIR_DOMAIN_DEVICE_LEASE; dev->type = VIR_DOMAIN_DEVICE_LEASE;
...@@ -7446,6 +7507,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, ...@@ -7446,6 +7507,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
nodes[i], nodes[i],
ctxt, ctxt,
bootMap, bootMap,
&def->seclabel,
flags); flags);
if (!disk) if (!disk)
goto error; goto error;
...@@ -9749,23 +9811,32 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def, ...@@ -9749,23 +9811,32 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def,
if (!sectype) if (!sectype)
goto cleanup; goto cleanup;
if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC && if (def->model &&
def->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
!def->baselabel && !def->baselabel &&
(flags & VIR_DOMAIN_XML_INACTIVE)) { (flags & VIR_DOMAIN_XML_INACTIVE)) {
/* This is the default for inactive xml, so nothing to output. */ /* This is the default for inactive xml, so nothing to output. */
} else { } else {
virBufferAsprintf(buf, "<seclabel type='%s' model='%s' relabel='%s'>\n", virBufferAddLit(buf, "<seclabel");
sectype, def->model, if (def->model)
virBufferAsprintf(buf, " type='%s' model='%s'",
sectype, def->model);
virBufferAsprintf(buf, " relabel='%s'",
def->norelabel ? "no" : "yes"); def->norelabel ? "no" : "yes");
virBufferEscapeString(buf, " <label>%s</label>\n", if (def->label || def->baselabel) {
def->label); virBufferAddLit(buf, ">\n");
if (!def->norelabel) virBufferEscapeString(buf, " <label>%s</label>\n",
virBufferEscapeString(buf, " <imagelabel>%s</imagelabel>\n", def->label);
def->imagelabel); if (!def->norelabel)
if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC) virBufferEscapeString(buf, " <imagelabel>%s</imagelabel>\n",
virBufferEscapeString(buf, " <baselabel>%s</baselabel>\n", def->imagelabel);
def->baselabel); if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
virBufferAddLit(buf, "</seclabel>\n"); virBufferEscapeString(buf, " <baselabel>%s</baselabel>\n",
def->baselabel);
virBufferAddLit(buf, "</seclabel>\n");
} else {
virBufferAddLit(buf, "/>\n");
}
} }
ret = 0; ret = 0;
cleanup: cleanup:
...@@ -9885,17 +9956,36 @@ virDomainDiskDefFormat(virBufferPtr buf, ...@@ -9885,17 +9956,36 @@ virDomainDiskDefFormat(virBufferPtr buf,
def->startupPolicy) { def->startupPolicy) {
switch (def->type) { switch (def->type) {
case VIR_DOMAIN_DISK_TYPE_FILE: case VIR_DOMAIN_DISK_TYPE_FILE:
virBufferAsprintf(buf," <source"); virBufferAddLit(buf, " <source");
if (def->src) if (def->src)
virBufferEscapeString(buf, " file='%s'", def->src); virBufferEscapeString(buf, " file='%s'", def->src);
if (def->startupPolicy) if (def->startupPolicy)
virBufferEscapeString(buf, " startupPolicy='%s'", virBufferEscapeString(buf, " startupPolicy='%s'",
startupPolicy); startupPolicy);
virBufferAsprintf(buf, "/>\n"); if (def->seclabel) {
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 8);
if (virSecurityLabelDefFormat(buf, def->seclabel, flags) < 0)
return -1;
virBufferAdjustIndent(buf, -8);
virBufferAddLit(buf, " </source>\n");
} else {
virBufferAddLit(buf, "/>\n");
}
break; break;
case VIR_DOMAIN_DISK_TYPE_BLOCK: case VIR_DOMAIN_DISK_TYPE_BLOCK:
virBufferEscapeString(buf, " <source dev='%s'/>\n", if (def->src && def->seclabel) {
def->src); virBufferEscapeString(buf, " <source dev='%s'>\n",
def->src);
virBufferAdjustIndent(buf, 8);
if (virSecurityLabelDefFormat(buf, def->seclabel, flags) < 0)
return -1;
virBufferAdjustIndent(buf, -8);
virBufferAddLit(buf, " </source>\n");
} else {
virBufferEscapeString(buf, " <source dev='%s'/>\n",
def->src);
}
break; break;
case VIR_DOMAIN_DISK_TYPE_DIR: case VIR_DOMAIN_DISK_TYPE_DIR:
virBufferEscapeString(buf, " <source dir='%s'/>\n", virBufferEscapeString(buf, " <source dir='%s'/>\n",
......
...@@ -357,6 +357,7 @@ struct _virDomainDiskDef { ...@@ -357,6 +357,7 @@ struct _virDomainDiskDef {
int device; int device;
int bus; int bus;
char *src; char *src;
virSecurityLabelDefPtr seclabel;
char *dst; char *dst;
int protocol; int protocol;
int nhosts; int nhosts;
......
LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
pc -m 214 -smp 1 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor,\
server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 \
-hdb /dev/HostVG/QEMUGuest2 -net none -serial \
none -parallel none -usb
...@@ -662,6 +662,7 @@ mymain(void) ...@@ -662,6 +662,7 @@ mymain(void)
DO_TEST("seclabel-dynamic", false, QEMU_CAPS_NAME); DO_TEST("seclabel-dynamic", false, QEMU_CAPS_NAME);
DO_TEST("seclabel-dynamic-baselabel", false, QEMU_CAPS_NAME); DO_TEST("seclabel-dynamic-baselabel", false, QEMU_CAPS_NAME);
DO_TEST("seclabel-dynamic-override", false, QEMU_CAPS_NAME);
DO_TEST("seclabel-static", false, QEMU_CAPS_NAME); DO_TEST("seclabel-static", false, QEMU_CAPS_NAME);
DO_TEST("seclabel-static-relabel", false, QEMU_CAPS_NAME); DO_TEST("seclabel-static-relabel", false, QEMU_CAPS_NAME);
......
...@@ -195,6 +195,7 @@ mymain(void) ...@@ -195,6 +195,7 @@ mymain(void)
DO_TEST("blkdeviotune"); DO_TEST("blkdeviotune");
DO_TEST("seclabel-dynamic-baselabel"); DO_TEST("seclabel-dynamic-baselabel");
DO_TEST("seclabel-dynamic-override");
DO_TEST("seclabel-static"); DO_TEST("seclabel-static");
/* These tests generate different XML */ /* These tests generate different XML */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册