提交 e9377dda 编写于 作者: M Marcelo Cerri 提交者: Michal Privoznik

Multiple security drivers in XML data

This patch updates the domain and capability XML parser and formatter to
support more than one "seclabel" element for each domain and device. The
RNG schema and the tests related to this are also updated by this patch.
Signed-off-by: NMarcelo Cerri <mhcerri@linux.vnet.ibm.com>
上级 6c3cf57d
......@@ -1275,8 +1275,8 @@
path to the file holding the disk. If the disk
<code>type</code> is "block", then the <code>dev</code>
attribute specifies the path to the host device to serve as
the disk. With both "file" and "block", an optional
sub-element <code>seclabel</code>, <a href="#seclabel">described
the disk. With both "file" and "block", one or more optional
sub-elements <code>seclabel</code>, <a href="#seclabel">described
below</a> (and <span class="since">since 0.9.9</span>), can be
used to override the domain security labeling policy for just
that source file. If the disk <code>type</code> is "dir", then the
......@@ -3919,6 +3919,13 @@ qemu-kvm -net nic,model=? /dev/null
since 0.6.2, and 'none' since 0.9.10.</span>
</p>
<p>
If more than one security driver is used by libvirt, multiple
<code>seclabel</code> tags can be used, one for each driver and
the security driver referenced by each tag can be defined using
the attribute <code>model</code>
</p>
<p>
Valid input XML configurations for the top-level security label
are:
......
......@@ -44,20 +44,22 @@
<optional>
<ref name='topology'/>
</optional>
<optional>
<zeroOrMore>
<ref name='secmodel'/>
</optional>
</zeroOrMore>
</element>
</define>
<define name='secmodel'>
<element name='secmodel'>
<element name='model'>
<text/>
</element>
<element name='doi'>
<text/>
</element>
<interleave>
<element name='model'>
<text/>
</element>
<element name='doi'>
<text/>
</element>
</interleave>
</element>
</define>
......
......@@ -55,9 +55,9 @@
<optional>
<ref name="devices"/>
</optional>
<optional>
<zeroOrMore>
<ref name="seclabel"/>
</optional>
</zeroOrMore>
<optional>
<ref name='qemucmdline'/>
</optional>
......@@ -148,18 +148,32 @@
<!-- A per-device seclabel override is more limited, either
relabel=no or a <label> must be present. -->
<choice>
<attribute name='relabel'>
<value>no</value>
</attribute>
<group>
<optional>
<attribute name='model'>
<text/>
</attribute>
</optional>
<attribute name='relabel'>
<value>no</value>
</attribute>
</group>
<group>
<optional>
<attribute name='model'>
<text/>
</attribute>
</optional>
<optional>
<attribute name='relabel'>
<value>yes</value>
</attribute>
</optional>
<element name='label'>
<text/>
</element>
<zeroOrMore>
<element name='label'>
<text/>
</element>
</zeroOrMore>
</group>
</choice>
</element>
......
......@@ -772,12 +772,12 @@ virCapabilitiesFormatXML(virCapsPtr caps)
virBufferAddLit(&xml, " </topology>\n");
}
if (caps->host.nsecModels) {
for (i = 0; i < caps->host.nsecModels; i++) {
virBufferAddLit(&xml, " <secmodel>\n");
virBufferAsprintf(&xml, " <model>%s</model>\n",
caps->host.secModels[0].model);
caps->host.secModels[i].model);
virBufferAsprintf(&xml, " <doi>%s</doi>\n",
caps->host.secModels[0].doi);
caps->host.secModels[i].doi);
virBufferAddLit(&xml, " </secmodel>\n");
}
......
......@@ -2985,17 +2985,19 @@ virDomainDiskDefAssignAddress(virCapsPtr caps, virDomainDiskDefPtr def)
return 0;
}
static int
virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
xmlXPathContextPtr ctxt,
static virSecurityLabelDefPtr
virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
unsigned int flags)
{
char *p;
virSecurityLabelDefPtr def = NULL;
if (virXPathNode("./seclabel[1]", ctxt) == NULL)
return 0;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
goto error;
}
p = virXPathStringLimit("string(./seclabel[1]/@type)",
p = virXPathStringLimit("string(./@type)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p == NULL) {
def->type = VIR_DOMAIN_SECLABEL_DYNAMIC;
......@@ -3009,7 +3011,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
}
}
p = virXPathStringLimit("string(./seclabel[1]/@relabel)",
p = virXPathStringLimit("string(./@relabel)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p != NULL) {
if (STREQ(p, "yes")) {
......@@ -3049,7 +3051,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
if (def->type == VIR_DOMAIN_SECLABEL_STATIC ||
(!(flags & VIR_DOMAIN_XML_INACTIVE) &&
def->type != VIR_DOMAIN_SECLABEL_NONE)) {
p = virXPathStringLimit("string(./seclabel[1]/label[1])",
p = virXPathStringLimit("string(./label[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p == NULL) {
virReportError(VIR_ERR_XML_ERROR,
......@@ -3064,7 +3066,7 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
if (!def->norelabel &&
(!(flags & VIR_DOMAIN_XML_INACTIVE) &&
def->type != VIR_DOMAIN_SECLABEL_NONE)) {
p = virXPathStringLimit("string(./seclabel[1]/imagelabel[1])",
p = virXPathStringLimit("string(./imagelabel[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p == NULL) {
virReportError(VIR_ERR_XML_ERROR,
......@@ -3076,93 +3078,179 @@ virSecurityLabelDefParseXML(virSecurityLabelDefPtr def,
/* Only parse baselabel for dynamic label type */
if (def->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
p = virXPathStringLimit("string(./seclabel[1]/baselabel[1])",
p = virXPathStringLimit("string(./baselabel[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
def->baselabel = p;
}
/* Only parse model, if static labelling, or a base
* label is set, or doing active XML
*/
if (def->type == VIR_DOMAIN_SECLABEL_STATIC ||
def->baselabel ||
(!(flags & VIR_DOMAIN_XML_INACTIVE) &&
def->type != VIR_DOMAIN_SECLABEL_NONE)) {
p = virXPathStringLimit("string(./seclabel[1]/@model)",
VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
if (p == NULL) {
virReportError(VIR_ERR_XML_ERROR,
"%s", _("missing security model"));
goto error;
}
def->model = p;
/* Always parse model */
p = virXPathStringLimit("string(./@model)",
VIR_SECURITY_MODEL_BUFLEN-1, ctxt);
if (p == NULL && def->type != VIR_DOMAIN_SECLABEL_NONE) {
virReportError(VIR_ERR_XML_ERROR,
"%s", _("missing security model"));
}
def->model = p;
return 0;
return def;
error:
virSecurityLabelDefFree(def);
return -1;
return NULL;
}
static int
virSecurityDeviceLabelDefParseXML(virSecurityDeviceLabelDefPtr *def,
virSecurityLabelDefPtr vmDef,
xmlXPathContextPtr ctxt)
virSecurityLabelDefsParseXML(virDomainDefPtr def,
xmlXPathContextPtr ctxt,
unsigned int flags)
{
char *p;
int i = 0, n;
xmlNodePtr *list = NULL, saved_node;
*def = NULL;
/* Check args and save context */
if (def == NULL || ctxt == NULL)
return 0;
saved_node = ctxt->node;
if (virXPathNode("./seclabel[1]", ctxt) == NULL)
/* Allocate a security labels based on XML */
if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0)
return 0;
/* Can't use overrides if top-level doesn't allow relabeling. */
if (vmDef && vmDef->norelabel) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("label overrides require relabeling to be "
"enabled at the domain level"));
return -1;
if (VIR_ALLOC_N(def->seclabels, n) < 0) {
virReportOOMError();
goto error;
}
if (VIR_ALLOC(*def) < 0) {
virReportOOMError();
return -1;
/* Parse each "seclabel" tag */
for (i = 0; i < n; i++) {
ctxt->node = list[i];
def->seclabels[i] = virSecurityLabelDefParseXML(ctxt, flags);
if (def->seclabels[i] == NULL)
goto error;
}
def->nseclabels = n;
ctxt->node = saved_node;
VIR_FREE(list);
p = virXPathStringLimit("string(./seclabel[1]/@relabel)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
if (p != NULL) {
if (STREQ(p, "yes")) {
(*def)->norelabel = false;
} else if (STREQ(p, "no")) {
(*def)->norelabel = true;
} else {
virReportError(VIR_ERR_XML_ERROR,
_("invalid security relabel value %s"), p);
VIR_FREE(p);
VIR_FREE(*def);
return -1;
/* Checking missing model information
* when there is more than one seclabel */
if (n > 1) {
for(; n; n--) {
if (def->seclabels[n - 1]->model == NULL) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing security model "
"when using multiple labels"));
goto error;
}
}
VIR_FREE(p);
} else {
(*def)->norelabel = false;
}
return 0;
p = virXPathStringLimit("string(./seclabel[1]/label[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
(*def)->label = p;
error:
ctxt->node = saved_node;
for (; i > 0; i--) {
virSecurityLabelDefFree(def->seclabels[i - 1]);
}
VIR_FREE(def->seclabels);
VIR_FREE(list);
return -1;
}
if ((*def)->label && (*def)->norelabel) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Cannot specify a label if relabelling is turned off"));
VIR_FREE((*def)->label);
VIR_FREE(*def);
return -1;
static int
virSecurityDeviceLabelDefParseXML(virDomainDiskDefPtr def,
virSecurityLabelDefPtr *vmSeclabels,
int nvmSeclabels, xmlXPathContextPtr ctxt)
{
int n, i, j;
xmlNodePtr *list = NULL;
virSecurityLabelDefPtr vmDef = NULL;
char *model, *relabel, *label;
if (def == NULL)
return 0;
if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) == 0)
return 0;
def->nseclabels = n;
if (VIR_ALLOC_N(def->seclabels, n) < 0) {
virReportOOMError();
goto error;
}
for (i = 0; i < n; i++) {
if (VIR_ALLOC(def->seclabels[i]) < 0) {
virReportOOMError();
goto error;
}
}
for (i = 0; i < n; i++) {
/* get model associated to this override */
model = virXMLPropString(list[i], "model");
if (model == NULL) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("invalid security model"));
goto error;
} else {
/* find the security label that it's being overriden */
for (j = 0; j < nvmSeclabels; j++) {
if (STREQ(vmSeclabels[j]->model, model)) {
vmDef = vmSeclabels[j];
break;
}
}
def->seclabels[i]->model = model;
}
/* Can't use overrides if top-level doesn't allow relabeling. */
if (vmDef && vmDef->norelabel) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("label overrides require relabeling to be "
"enabled at the domain level"));
goto error;
}
relabel = virXMLPropString(list[i], "relabel");
if (relabel != NULL) {
if (STREQ(relabel, "yes")) {
def->seclabels[i]->norelabel = false;
} else if (STREQ(relabel, "no")) {
def->seclabels[i]->norelabel = true;
} else {
virReportError(VIR_ERR_XML_ERROR,
_("invalid security relabel value %s"),
relabel);
VIR_FREE(relabel);
goto error;
}
VIR_FREE(relabel);
} else {
def->seclabels[i]->norelabel = false;
}
ctxt->node = list[i];
label = virXPathStringLimit("string(./label)",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
def->seclabels[i]->label = label;
if (label && def->seclabels[i]->norelabel) {
virReportError(VIR_ERR_XML_ERROR,
_("Cannot specify a label if relabelling is "
"turned off. model=%s"),
def->seclabels[i]->model);
goto error;
}
}
VIR_FREE(list);
return 0;
error:
for (i = 0; i < n; i++) {
virSecurityDeviceLabelDefFree(def->seclabels[i]);
}
VIR_FREE(def->seclabels);
VIR_FREE(list);
return -1;
}
......@@ -3246,7 +3334,8 @@ virDomainDiskDefParseXML(virCapsPtr caps,
xmlNodePtr node,
xmlXPathContextPtr ctxt,
virBitmapPtr bootMap,
virSecurityLabelDefPtr vmSeclabel,
virSecurityLabelDefPtr* vmSeclabels,
int nvmSeclabels,
unsigned int flags)
{
virDomainDiskDefPtr def;
......@@ -3584,15 +3673,10 @@ virDomainDiskDefParseXML(virCapsPtr caps,
if (sourceNode) {
xmlNodePtr saved_node = ctxt->node;
ctxt->node = sourceNode;
if ((VIR_ALLOC(def->seclabels) < 0)) {
virReportOOMError();
goto error;
}
if (virSecurityDeviceLabelDefParseXML(&def->seclabels[0],
vmSeclabel,
if (virSecurityDeviceLabelDefParseXML(def, vmSeclabels,
nvmSeclabels,
ctxt) < 0)
goto error;
def->nseclabels = 1;
ctxt->node = saved_node;
}
......@@ -7064,18 +7148,11 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
goto error;
}
if (!def->seclabels) {
if ((VIR_ALLOC(def->seclabels) < 0) ||
(VIR_ALLOC(def->seclabels[0])) < 0 ) {
virReportOOMError();
goto error;
}
}
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
dev->type = VIR_DOMAIN_DEVICE_DISK;
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node, ctxt,
NULL, def->seclabels[0],
NULL, def->seclabels,
def->nseclabels,
flags)))
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
......@@ -8014,13 +8091,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
/* analysis of security label, done early even though we format it
* late, so devices can refer to this for defaults */
if ((VIR_ALLOC(def->seclabels) < 0) ||
(VIR_ALLOC(def->seclabels[0]) < 0)) {
virReportOOMError();
goto error;
}
def->nseclabels = 1;
if (virSecurityLabelDefParseXML(def->seclabels[0], ctxt, flags) == -1)
if (virSecurityLabelDefsParseXML(def, ctxt, flags) == -1)
goto error;
/* Extract domain memory */
......@@ -8620,7 +8691,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
nodes[i],
ctxt,
bootMap,
def->seclabels[0],
def->seclabels,
def->nseclabels,
flags);
if (!disk)
goto error;
......@@ -10975,13 +11047,14 @@ virSecurityLabelDefFormat(virBufferPtr buf, virSecurityLabelDefPtr def)
virBufferAsprintf(buf, "<seclabel type='%s'",
sectype);
if (def->model)
virBufferEscapeString(buf, " model='%s'", def->model);
if (def->type == VIR_DOMAIN_SECLABEL_NONE) {
virBufferAddLit(buf, "/>\n");
return;
}
virBufferEscapeString(buf, " model='%s'", def->model);
virBufferAsprintf(buf, " relabel='%s'",
def->norelabel ? "no" : "yes");
......@@ -11007,8 +11080,8 @@ static void
virSecurityDeviceLabelDefFormat(virBufferPtr buf,
virSecurityDeviceLabelDefPtr def)
{
virBufferAsprintf(buf, "<seclabel relabel='%s'",
def->norelabel ? "no" : "yes");
virBufferAsprintf(buf, "<seclabel model='%s' relabel='%s'",
def->model, def->norelabel ? "no" : "yes");
if (def->label) {
virBufferAddLit(buf, ">\n");
virBufferEscapeString(buf, " <label>%s</label>\n",
......@@ -11053,6 +11126,7 @@ virDomainDiskDefFormat(virBufferPtr buf,
const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read);
const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy);
int n;
char uuidstr[VIR_UUID_STRING_BUFLEN];
if (!type) {
......@@ -11148,10 +11222,11 @@ virDomainDiskDefFormat(virBufferPtr buf,
if (def->startupPolicy)
virBufferEscapeString(buf, " startupPolicy='%s'",
startupPolicy);
if (def->seclabels && def->seclabels[0]) {
if (def->nseclabels) {
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 8);
virSecurityDeviceLabelDefFormat(buf, def->seclabels[0]);
for (n = 0; n < def->nseclabels; n++)
virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
virBufferAdjustIndent(buf, -8);
virBufferAddLit(buf, " </source>\n");
} else {
......@@ -11161,10 +11236,11 @@ virDomainDiskDefFormat(virBufferPtr buf,
case VIR_DOMAIN_DISK_TYPE_BLOCK:
virBufferEscapeString(buf, " <source dev='%s'",
def->src);
if (def->seclabels && def->seclabels[0]) {
if (def->nseclabels) {
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 8);
virSecurityDeviceLabelDefFormat(buf, def->seclabels[0]);
for (n = 0; n < def->nseclabels; n++)
virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
virBufferAdjustIndent(buf, -8);
virBufferAddLit(buf, " </source>\n");
} else {
......@@ -13158,11 +13234,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virBufferAddLit(buf, " </devices>\n");
if (def->nseclabels && def->seclabels) {
virBufferAdjustIndent(buf, 2);
virSecurityLabelDefFormat(buf, def->seclabels[0]);
virBufferAdjustIndent(buf, -2);
}
virBufferAdjustIndent(buf, 2);
for (n = 0; n < def->nseclabels; n++)
virSecurityLabelDefFormat(buf, def->seclabels[n]);
virBufferAdjustIndent(buf, -2);
if (def->namespaceData && def->ns.format) {
if ((def->ns.format)(buf, def->namespaceData) < 0)
......@@ -15529,3 +15604,65 @@ cleanup:
}
return ret;
}
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model)
{
int i;
if (def == NULL || model == NULL)
return NULL;
for (i = 0; i < def->nseclabels; i++) {
if (def->seclabels[i]->model == NULL)
continue;
if (STREQ(def->seclabels[i]->model, model))
return def->seclabels[i];
}
return virDomainDefAddSecurityLabelDef(def, model);
}
virSecurityDeviceLabelDefPtr
virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model)
{
int i;
if (def == NULL)
return NULL;
for (i = 0; i < def->nseclabels; i++) {
if (STREQ(def->seclabels[i]->model, model))
return def->seclabels[i];
}
return NULL;
}
virSecurityLabelDefPtr
virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model)
{
virSecurityLabelDefPtr seclabel = NULL;
if (VIR_ALLOC(seclabel) < 0) {
virReportOOMError();
return NULL;
}
if (model) {
seclabel->model = strdup(model);
if (seclabel->model == NULL) {
virReportOOMError();
virSecurityLabelDefFree(seclabel);
return NULL;
}
}
if (VIR_EXPAND_N(def->seclabels, def->nseclabels, 1) < 0) {
virReportOOMError();
virSecurityLabelDefFree(seclabel);
return NULL;
}
def->seclabels[def->nseclabels - 1] = seclabel;
return seclabel;
}
......@@ -2143,6 +2143,15 @@ virDomainState
virDomainObjGetState(virDomainObjPtr obj, int *reason)
ATTRIBUTE_NONNULL(1);
virSecurityLabelDefPtr
virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model);
virSecurityDeviceLabelDefPtr
virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model);
virSecurityLabelDefPtr
virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model);
typedef const char* (*virLifecycleToStringFunc)(int type);
typedef int (*virLifecycleFromStringFunc)(const char *type);
......
......@@ -300,6 +300,9 @@ virDomainDefCompatibleDevice;
virDomainDefFormat;
virDomainDefFormatInternal;
virDomainDefFree;
virDomainDefGetSecurityLabelDef;
virDomainDiskDefGetSecurityLabelDef;
virDomainDefAddSecurityLabelDef;
virDomainDefParseFile;
virDomainDefParseNode;
virDomainDefParseString;
......
......@@ -16,14 +16,14 @@
<emulator>/usr/bin/qemu</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'>
<seclabel relabel='no'/>
<seclabel model='selinux' relabel='no'/>
</source>
<target dev='hda' bus='ide'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest2'>
<seclabel relabel='yes'>
<seclabel model='selinux' relabel='yes'>
<label>system_u:system_r:public_content_t:s0</label>
</seclabel>
</source>
......
......@@ -22,5 +22,5 @@
<controller type='ide' index='0'/>
<memballoon model='virtio'/>
</devices>
<seclabel type='dynamic' relabel='yes'/>
<seclabel model='selinux' type='dynamic' relabel='yes'/>
</domain>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册