1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-03-20 07:59:00 +00:00

Allow for resource relabelling with static labels

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.
This commit is contained in:
Daniel P. Berrange 2011-06-24 10:21:33 +01:00
parent 4ebfc42716
commit 6321fd9798
6 changed files with 149 additions and 73 deletions

View File

@ -61,6 +61,12 @@
<value>static</value> <value>static</value>
</choice> </choice>
</attribute> </attribute>
<attribute name="relabel">
<choice>
<value>yes</value>
<value>no</value>
</choice>
</attribute>
<element name="label"> <element name="label">
<text/> <text/>
</element> </element>

View File

@ -5072,6 +5072,30 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def,
"%s", _("invalid security type")); "%s", _("invalid security type"));
goto error; 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 relabeling"));
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 /* Only parse label, if using static labels, or
* if the 'live' VM XML is requested * if the 'live' VM XML is requested
@ -5089,8 +5113,8 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def,
def->seclabel.label = p; def->seclabel.label = p;
} }
/* Only parse imagelabel, if requested live XML for dynamic label */ /* Only parse imagelabel, if requested live XML with relabeling */
if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && if (def->seclabel.relabel &&
!(flags & VIR_DOMAIN_XML_INACTIVE)) { !(flags & VIR_DOMAIN_XML_INACTIVE)) {
p = virXPathStringLimit("string(./seclabel/imagelabel[1])", p = virXPathStringLimit("string(./seclabel/imagelabel[1])",
VIR_SECURITY_LABEL_BUFLEN-1, ctxt); VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
@ -9864,16 +9888,17 @@ char *virDomainDefFormat(virDomainDefPtr def,
if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
!def->seclabel.baselabel && !def->seclabel.baselabel &&
(flags & VIR_DOMAIN_XML_INACTIVE)) { (flags & VIR_DOMAIN_XML_INACTIVE)) {
virBufferAsprintf(&buf, " <seclabel type='%s' model='%s'/>\n", virBufferAsprintf(&buf, " <seclabel type='%s' model='%s' relabel='%s'/>\n",
sectype, def->seclabel.model); sectype, def->seclabel.model,
def->seclabel.relabel ? "yes" : "no");
} else { } else {
virBufferAsprintf(&buf, " <seclabel type='%s' model='%s'>\n", virBufferAsprintf(&buf, " <seclabel type='%s' model='%s' relabel='%s'>\n",
sectype, def->seclabel.model); sectype, def->seclabel.model,
def->seclabel.relabel ? "yes" : "no");
if (def->seclabel.label) if (def->seclabel.label)
virBufferEscapeString(&buf, " <label>%s</label>\n", virBufferEscapeString(&buf, " <label>%s</label>\n",
def->seclabel.label); def->seclabel.label);
if (def->seclabel.imagelabel && if (def->seclabel.relabel && def->seclabel.imagelabel)
(def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC))
virBufferEscapeString(&buf, " <imagelabel>%s</imagelabel>\n", virBufferEscapeString(&buf, " <imagelabel>%s</imagelabel>\n",
def->seclabel.imagelabel); def->seclabel.imagelabel);
if (def->seclabel.baselabel && if (def->seclabel.baselabel &&

View File

@ -959,7 +959,8 @@ struct _virSecurityLabelDef {
char *label; /* security label string */ char *label; /* security label string */
char *imagelabel; /* security image label string */ char *imagelabel; /* security image label string */
char *baselabel; /* base name of label string */ char *baselabel; /* base name of label string */
int type; int type; /* virDomainSeclabelType */
bool relabel;
}; };
enum virDomainTimerNameType { enum virDomainTimerNameType {

View File

@ -2886,8 +2886,8 @@ void qemuProcessStop(struct qemud_driver *driver,
if (!vm->def->seclabel.baselabel) if (!vm->def->seclabel.baselabel)
VIR_FREE(vm->def->seclabel.model); VIR_FREE(vm->def->seclabel.model);
VIR_FREE(vm->def->seclabel.label); VIR_FREE(vm->def->seclabel.label);
VIR_FREE(vm->def->seclabel.imagelabel);
} }
VIR_FREE(vm->def->seclabel.imagelabel);
virDomainDefClearDeviceAliases(vm->def); virDomainDefClearDeviceAliases(vm->def);
if (!priv->persistentAddrs) { if (!priv->persistentAddrs) {

View File

@ -265,7 +265,7 @@ reload_profile(virSecurityManagerPtr mgr,
int rc = -1; int rc = -1;
char *profile_name = NULL; char *profile_name = NULL;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
if ((profile_name = get_profile_name(vm)) == NULL) if ((profile_name = get_profile_name(vm)) == NULL)
@ -461,7 +461,7 @@ static int
AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr, AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainObjPtr vm, const char *stdin_path) virDomainObjPtr vm, const char *stdin_path)
{ {
if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) if (!vm->def->seclabel.relabel)
return 0; return 0;
/* Reload the profile if stdin_path is specified. Note that /* Reload the profile if stdin_path is specified. Note that
@ -610,7 +610,7 @@ AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
int rc = -1; int rc = -1;
char *profile_name; char *profile_name;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
@ -682,7 +682,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
struct SDPDOP *ptr; struct SDPDOP *ptr;
int ret = -1; int ret = -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@ -741,7 +741,7 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
{ {
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
return reload_profile(mgr, vm, NULL, false); return reload_profile(mgr, vm, NULL, false);

View File

@ -165,13 +165,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
virDomainObjPtr vm) virDomainObjPtr vm)
{ {
int rc = -1; int rc = -1;
char mcs[1024]; char *mcs = NULL;
char *scontext = NULL; char *scontext = NULL;
int c1 = 0; int c1 = 0;
int c2 = 0; int c2 = 0;
context_t ctx = NULL;
if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
return 0;
if ((vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && if ((vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
!vm->def->seclabel.baselabel && !vm->def->seclabel.baselabel &&
@ -181,13 +179,19 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
return rc; return rc;
} }
if (vm->def->seclabel.label || if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
vm->def->seclabel.imagelabel) { vm->def->seclabel.label) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("security label already defined for VM")); "%s", _("security label already defined for VM"));
return rc; 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 && if (vm->def->seclabel.model &&
STRNEQ(vm->def->seclabel.model, SECURITY_SELINUX_NAME)) { STRNEQ(vm->def->seclabel.model, SECURITY_SELINUX_NAME)) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
@ -196,51 +200,89 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
return rc; return rc;
} }
do { if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) {
c1 = virRandom(1024); if (!(ctx = context_new(vm->def->seclabel.label)) ) {
c2 = virRandom(1024); virReportSystemError(errno,
_("unable to allocate socket security context '%s'"),
if ( c1 == c2 ) { vm->def->seclabel.label);
snprintf(mcs, sizeof(mcs), "s0:c%d", c1); return rc;
} 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);
} }
} while(mcsAdd(mcs) == -1);
vm->def->seclabel.label = const char *range = context_range_get(ctx);
SELinuxGenNewContext(vm->def->seclabel.baselabel ? if (!range ||
vm->def->seclabel.baselabel : !(mcs = strdup(range))) {
default_domain_context, mcs); virReportOOMError();
if (! vm->def->seclabel.label) { goto cleanup;
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, }
_("cannot generate selinux context for %s"), mcs); } else {
goto err; 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); vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
if (! vm->def->seclabel.imagelabel) { if (!vm->def->seclabel.imagelabel) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot generate selinux context for %s"), mcs); _("cannot generate selinux context for %s"), mcs);
goto err; goto cleanup;
} }
if (!vm->def->seclabel.model && if (!vm->def->seclabel.model &&
!(vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) { !(vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) {
virReportOOMError(); virReportOOMError();
goto err; goto cleanup;
} }
rc = 0; rc = 0;
goto done;
err: cleanup:
VIR_FREE(vm->def->seclabel.label); if (rc != 0) {
VIR_FREE(vm->def->seclabel.imagelabel); if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)
if (!vm->def->seclabel.baselabel) VIR_FREE(vm->def->seclabel.label);
VIR_FREE(vm->def->seclabel.model); VIR_FREE(vm->def->seclabel.imagelabel);
done: 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(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; return rc;
} }
@ -495,7 +537,7 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
{ {
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
/* Don't restore labels on readoly/shared disks, because /* Don't restore labels on readoly/shared disks, because
@ -579,7 +621,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
return virDomainDiskDefForeachPath(disk, return virDomainDiskDefForeachPath(disk,
@ -619,7 +661,7 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
int ret = -1; int ret = -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@ -688,7 +730,7 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
int ret = -1; int ret = -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@ -742,7 +784,7 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm,
char *in = NULL, *out = NULL; char *in = NULL, *out = NULL;
int ret = -1; int ret = -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
switch (dev->type) { switch (dev->type) {
@ -788,7 +830,7 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm,
char *in = NULL, *out = NULL; char *in = NULL, *out = NULL;
int ret = -1; int ret = -1;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
switch (dev->type) { switch (dev->type) {
@ -876,7 +918,7 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
VIR_DEBUG("Restoring security label on %s", vm->def->name); VIR_DEBUG("Restoring security label on %s", vm->def->name);
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
for (i = 0 ; i < vm->def->nhostdevs ; i++) { for (i = 0 ; i < vm->def->nhostdevs ; i++) {
@ -922,18 +964,18 @@ SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
{ {
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC || if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
secdef->label == NULL) if (secdef->label != NULL) {
return 0; context_t con = context_new(secdef->label);
if (con) {
context_t con = context_new(secdef->label); mcsRemove(context_range_get(con));
if (con) { context_free(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); VIR_FREE(secdef->imagelabel);
return 0; return 0;
@ -947,7 +989,7 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
{ {
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
return SELinuxSetFilecon(savefile, secdef->imagelabel); return SELinuxSetFilecon(savefile, secdef->imagelabel);
@ -961,7 +1003,7 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
{ {
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
return SELinuxRestoreSecurityFileLabel(savefile); return SELinuxRestoreSecurityFileLabel(savefile);
@ -1176,7 +1218,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
const virSecurityLabelDefPtr secdef = &vm->def->seclabel; const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
int i; int i;
if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) if (!secdef->relabel)
return 0; return 0;
for (i = 0 ; i < vm->def->ndisks ; i++) { for (i = 0 ; i < vm->def->ndisks ; i++) {
@ -1190,6 +1232,8 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
vm, vm->def->disks[i]) < 0) vm, vm->def->disks[i]) < 0)
return -1; return -1;
} }
/* XXX fixme process vm->def->fss if relabel == true */
for (i = 0 ; i < vm->def->nhostdevs ; i++) { for (i = 0 ; i < vm->def->nhostdevs ; i++) {
if (SELinuxSetSecurityHostdevLabel(mgr, if (SELinuxSetSecurityHostdevLabel(mgr,
vm, vm,