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