mirror of https://gitee.com/openkylin/libvirt.git
Add <seclabel> to character devices.
This allows the user to control labelling of each character device separately (the default is to inherit from the VM). Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
This commit is contained in:
parent
db2aff6ada
commit
f8b08d0e96
|
@ -3444,6 +3444,14 @@ qemu-kvm -net nic,model=? /dev/null
|
|||
configured by the <code>source</code> element.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>source</code> element may contain an optional
|
||||
<code>seclabel</code> to override the way that labelling
|
||||
is done on the socket path. If this element is not present,
|
||||
the <a href="#seclabel">security label is inherited from
|
||||
the per-domain setting</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each character device element has an optional
|
||||
sub-element <code><address></code> which can tie the
|
||||
|
|
|
@ -2454,6 +2454,9 @@
|
|||
<optional>
|
||||
<attribute name="wiremode"/>
|
||||
</optional>
|
||||
<optional>
|
||||
<ref name='devSeclabel'/>
|
||||
</optional>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
|
|
|
@ -1278,6 +1278,8 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src,
|
|||
|
||||
void virDomainChrDefFree(virDomainChrDefPtr def)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!def)
|
||||
return;
|
||||
|
||||
|
@ -1301,6 +1303,12 @@ void virDomainChrDefFree(virDomainChrDefPtr def)
|
|||
virDomainChrSourceDefClear(&def->source);
|
||||
virDomainDeviceInfoClear(&def->info);
|
||||
|
||||
if (def->seclabels) {
|
||||
for (i = 0; i < def->nseclabels; i++)
|
||||
virSecurityDeviceLabelDefFree(def->seclabels[i]);
|
||||
VIR_FREE(def->seclabels);
|
||||
}
|
||||
|
||||
VIR_FREE(def);
|
||||
}
|
||||
|
||||
|
@ -5353,7 +5361,11 @@ error:
|
|||
* <target>, which is used by <serial> but not <smartcard>). */
|
||||
static int
|
||||
virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
|
||||
xmlNodePtr cur, unsigned int flags)
|
||||
xmlNodePtr cur, unsigned int flags,
|
||||
virDomainChrDefPtr chr_def,
|
||||
xmlXPathContextPtr ctxt,
|
||||
virSecurityLabelDefPtr* vmSeclabels,
|
||||
int nvmSeclabels)
|
||||
{
|
||||
char *bindHost = NULL;
|
||||
char *bindService = NULL;
|
||||
|
@ -5408,6 +5420,21 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
|
|||
if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
|
||||
VIR_FREE(mode);
|
||||
}
|
||||
|
||||
/* Check for an optional seclabel override in <source/>. */
|
||||
if (chr_def) {
|
||||
xmlNodePtr saved_node = ctxt->node;
|
||||
ctxt->node = cur;
|
||||
if (virSecurityDeviceLabelDefParseXML(&chr_def->seclabels,
|
||||
&chr_def->nseclabels,
|
||||
vmSeclabels,
|
||||
nvmSeclabels,
|
||||
ctxt) < 0) {
|
||||
ctxt->node = saved_node;
|
||||
goto error;
|
||||
}
|
||||
ctxt->node = saved_node;
|
||||
}
|
||||
} else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
|
||||
if (protocol == NULL)
|
||||
protocol = virXMLPropString(cur, "type");
|
||||
|
@ -5601,7 +5628,10 @@ virDomainChrDefNew(void) {
|
|||
static virDomainChrDefPtr
|
||||
virDomainChrDefParseXML(virCapsPtr caps,
|
||||
virDomainDefPtr vmdef,
|
||||
xmlXPathContextPtr ctxt,
|
||||
xmlNodePtr node,
|
||||
virSecurityLabelDefPtr* vmSeclabels,
|
||||
int nvmSeclabels,
|
||||
unsigned int flags)
|
||||
{
|
||||
xmlNodePtr cur;
|
||||
|
@ -5632,7 +5662,9 @@ virDomainChrDefParseXML(virCapsPtr caps,
|
|||
}
|
||||
|
||||
cur = node->children;
|
||||
remaining = virDomainChrSourceDefParseXML(&def->source, cur, flags);
|
||||
remaining = virDomainChrSourceDefParseXML(&def->source, cur, flags,
|
||||
def, ctxt,
|
||||
vmSeclabels, nvmSeclabels);
|
||||
if (remaining < 0)
|
||||
goto error;
|
||||
if (remaining) {
|
||||
|
@ -5769,7 +5801,8 @@ virDomainSmartcardDefParseXML(xmlNodePtr node,
|
|||
}
|
||||
|
||||
cur = node->children;
|
||||
if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags) < 0)
|
||||
if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
|
||||
NULL, NULL, NULL, 0) < 0)
|
||||
goto error;
|
||||
|
||||
if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
|
||||
|
@ -7250,7 +7283,8 @@ virDomainRedirdevDefParseXML(const xmlNodePtr node,
|
|||
if (xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||
int remaining;
|
||||
|
||||
remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags);
|
||||
remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags,
|
||||
NULL, NULL, NULL, 0);
|
||||
if (remaining != 0)
|
||||
goto error;
|
||||
}
|
||||
|
@ -9319,7 +9353,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||
for (i = 0 ; i < n ; i++) {
|
||||
virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
|
||||
def,
|
||||
ctxt,
|
||||
nodes[i],
|
||||
def->seclabels,
|
||||
def->nseclabels,
|
||||
flags);
|
||||
if (!chr)
|
||||
goto error;
|
||||
|
@ -9346,7 +9383,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||
for (i = 0 ; i < n ; i++) {
|
||||
virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
|
||||
def,
|
||||
ctxt,
|
||||
nodes[i],
|
||||
def->seclabels,
|
||||
def->nseclabels,
|
||||
flags);
|
||||
if (!chr)
|
||||
goto error;
|
||||
|
@ -9376,7 +9416,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||
bool create_stub = true;
|
||||
virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
|
||||
def,
|
||||
ctxt,
|
||||
nodes[i],
|
||||
def->seclabels,
|
||||
def->nseclabels,
|
||||
flags);
|
||||
if (!chr)
|
||||
goto error;
|
||||
|
@ -9452,7 +9495,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||
for (i = 0 ; i < n ; i++) {
|
||||
virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
|
||||
def,
|
||||
ctxt,
|
||||
nodes[i],
|
||||
def->seclabels,
|
||||
def->nseclabels,
|
||||
flags);
|
||||
if (!chr)
|
||||
goto error;
|
||||
|
@ -12396,6 +12442,7 @@ virDomainChrDefFormat(virBufferPtr buf,
|
|||
const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
|
||||
def->targetType);
|
||||
bool tty_compat;
|
||||
size_t n;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
|
@ -12475,6 +12522,14 @@ virDomainChrDefFormat(virBufferPtr buf,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Security label overrides, if any. */
|
||||
if (def->seclabels && def->nseclabels > 0) {
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
for (n = 0; n < def->nseclabels; n++)
|
||||
virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
}
|
||||
|
||||
virBufferAsprintf(buf, " </%s>\n", elementName);
|
||||
|
||||
return ret;
|
||||
|
@ -15310,6 +15365,21 @@ virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
virSecurityDeviceLabelDefPtr
|
||||
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (def == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < def->nseclabels; i++) {
|
||||
if (STREQ_NULLABLE(def->seclabels[i]->model, model))
|
||||
return def->seclabels[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virSecurityLabelDefPtr
|
||||
virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model)
|
||||
{
|
||||
|
|
|
@ -966,6 +966,9 @@ struct _virDomainChrDef {
|
|||
virDomainChrSourceDef source;
|
||||
|
||||
virDomainDeviceInfo info;
|
||||
|
||||
size_t nseclabels;
|
||||
virSecurityDeviceLabelDefPtr *seclabels;
|
||||
};
|
||||
|
||||
enum virDomainSmartcardType {
|
||||
|
@ -2135,6 +2138,9 @@ virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model);
|
|||
virSecurityDeviceLabelDefPtr
|
||||
virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model);
|
||||
|
||||
virSecurityDeviceLabelDefPtr
|
||||
virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model);
|
||||
|
||||
virSecurityLabelDefPtr
|
||||
virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model);
|
||||
|
||||
|
|
|
@ -1213,38 +1213,61 @@ done:
|
|||
|
||||
static int
|
||||
virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
|
||||
virDomainChrSourceDefPtr dev)
|
||||
virDomainChrDefPtr dev,
|
||||
virDomainChrSourceDefPtr dev_source)
|
||||
|
||||
{
|
||||
virSecurityLabelDefPtr secdef;
|
||||
virSecurityLabelDefPtr seclabel;
|
||||
virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
|
||||
char *imagelabel = NULL;
|
||||
char *in = NULL, *out = NULL;
|
||||
int ret = -1;
|
||||
|
||||
secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
|
||||
if (secdef == NULL)
|
||||
seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
|
||||
if (seclabel == NULL)
|
||||
return -1;
|
||||
|
||||
if (secdef->norelabel)
|
||||
if (dev)
|
||||
chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
|
||||
SECURITY_SELINUX_NAME);
|
||||
|
||||
if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
|
||||
return 0;
|
||||
|
||||
switch (dev->type) {
|
||||
if (chr_seclabel)
|
||||
imagelabel = chr_seclabel->label;
|
||||
if (!imagelabel)
|
||||
imagelabel = seclabel->imagelabel;
|
||||
|
||||
switch (dev_source->type) {
|
||||
case VIR_DOMAIN_CHR_TYPE_DEV:
|
||||
case VIR_DOMAIN_CHR_TYPE_FILE:
|
||||
ret = virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel);
|
||||
ret = virSecuritySELinuxSetFilecon(dev_source->data.file.path,
|
||||
imagelabel);
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
||||
if (!dev_source->data.nix.listen) {
|
||||
if (virSecuritySELinuxSetFilecon(dev_source->data.file.path,
|
||||
imagelabel) < 0)
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
||||
if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
|
||||
(virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
|
||||
if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
|
||||
(virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0)) {
|
||||
virReportOOMError();
|
||||
goto done;
|
||||
}
|
||||
if (virFileExists(in) && virFileExists(out)) {
|
||||
if ((virSecuritySELinuxSetFilecon(in, secdef->imagelabel) < 0) ||
|
||||
(virSecuritySELinuxSetFilecon(out, secdef->imagelabel) < 0)) {
|
||||
if ((virSecuritySELinuxSetFilecon(in, imagelabel) < 0) ||
|
||||
(virSecuritySELinuxSetFilecon(out, imagelabel) < 0)) {
|
||||
goto done;
|
||||
}
|
||||
} else if (virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) {
|
||||
} else if (virSecuritySELinuxSetFilecon(dev_source->data.file.path,
|
||||
imagelabel) < 0) {
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -1263,30 +1286,44 @@ done:
|
|||
|
||||
static int
|
||||
virSecuritySELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
|
||||
virDomainChrSourceDefPtr dev)
|
||||
virDomainChrDefPtr dev,
|
||||
virDomainChrSourceDefPtr dev_source)
|
||||
|
||||
{
|
||||
virSecurityLabelDefPtr secdef;
|
||||
virSecurityLabelDefPtr seclabel;
|
||||
virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
|
||||
char *in = NULL, *out = NULL;
|
||||
int ret = -1;
|
||||
|
||||
secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
|
||||
if (secdef == NULL)
|
||||
seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
|
||||
if (seclabel == NULL)
|
||||
return -1;
|
||||
|
||||
if (secdef->norelabel)
|
||||
if (dev)
|
||||
chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
|
||||
SECURITY_SELINUX_NAME);
|
||||
if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
|
||||
return 0;
|
||||
|
||||
switch (dev->type) {
|
||||
switch (dev_source->type) {
|
||||
case VIR_DOMAIN_CHR_TYPE_DEV:
|
||||
case VIR_DOMAIN_CHR_TYPE_FILE:
|
||||
if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0)
|
||||
if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0)
|
||||
goto done;
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_UNIX:
|
||||
if (!dev_source->data.nix.listen) {
|
||||
if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0)
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_CHR_TYPE_PIPE:
|
||||
if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
|
||||
(virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
|
||||
if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
|
||||
(virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0)) {
|
||||
virReportOOMError();
|
||||
goto done;
|
||||
}
|
||||
|
@ -1295,7 +1332,7 @@ virSecuritySELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
|
|||
(virSecuritySELinuxRestoreSecurityFileLabel(in) < 0)) {
|
||||
goto done;
|
||||
}
|
||||
} else if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) {
|
||||
} else if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0) {
|
||||
goto done;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -1323,7 +1360,8 @@ virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
|
|||
dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
|
||||
return 0;
|
||||
|
||||
return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->source);
|
||||
return virSecuritySELinuxRestoreSecurityChardevLabel(def, dev,
|
||||
&dev->source);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1345,7 +1383,7 @@ virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
|
|||
return virSecuritySELinuxRestoreSecurityFileLabel(database);
|
||||
|
||||
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
|
||||
return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->data.passthru);
|
||||
return virSecuritySELinuxRestoreSecurityChardevLabel(def, NULL, &dev->data.passthru);
|
||||
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
|
@ -1703,7 +1741,7 @@ virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
|
|||
dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
|
||||
return 0;
|
||||
|
||||
return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->source);
|
||||
return virSecuritySELinuxSetSecurityChardevLabel(def, dev, &dev->source);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1727,7 +1765,7 @@ virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
|
|||
return virSecuritySELinuxSetFilecon(database, data->content_context);
|
||||
|
||||
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
|
||||
return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
|
||||
return virSecuritySELinuxSetSecurityChardevLabel(def, NULL, &dev->data.passthru);
|
||||
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
|
|
Loading…
Reference in New Issue