From: Daniel Walsh <dwalsh(a)redhat.com>
Currently the SELinux driver stores its state in a set of global
variables. This switches it to use a private data struct instead.
This will enable different instances to have their own data.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/security/security_selinux.c | 173 ++++++++++++++++++++++++---------------
1 file changed, 106 insertions(+), 67 deletions(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 4bd33a5..7202e71 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2011 Red Hat, Inc.
+ * Copyright (C) 2008-2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,12 +33,30 @@
#include "storage_file.h"
#include "virfile.h"
#include "virrandom.h"
+#include "util.h"
+#include "conf.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY
-static char default_domain_context[1024];
-static char default_content_context[1024];
-static char default_image_context[1024];
+#define MAX_CONTEXT 1024
+
+typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
+typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;
+
+typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
+typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;
+
+struct _virSecuritySELinuxData {
+ char *domain_context;
+ char *file_context;
+ char *content_context;
+};
+
+struct _virSecuritySELinuxCallbackData {
+ virSecurityManagerPtr manager;
+ virSecurityLabelDefPtr secdef;
+};
+
#define SECURITY_SELINUX_VOID_DOI "0"
#define SECURITY_SELINUX_NAME "selinux"
@@ -109,60 +127,51 @@ err:
}
static int
-SELinuxInitialize(void)
+SELinuxInitialize(virSecurityManagerPtr mgr)
{
- char *ptr = NULL;
- int fd = 0;
+ char *ptr;
+ virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
- fd = open(selinux_virtual_domain_context_path(), O_RDONLY);
- if (fd < 0) {
+ if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT,
&(data->domain_context)) < 0) {
virReportSystemError(errno,
- _("cannot open SELinux virtual domain context file
'%s'"),
+ _("cannot read SELinux virtual domain context file
'%s'"),
selinux_virtual_domain_context_path());
- return -1;
+ goto error;
}
- if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) {
- virReportSystemError(errno,
- _("cannot read SELinux virtual domain context file
%s"),
- selinux_virtual_domain_context_path());
- VIR_FORCE_CLOSE(fd);
- return -1;
- }
- VIR_FORCE_CLOSE(fd);
-
- ptr = strchrnul(default_domain_context, '\n');
- *ptr = '\0';
-
- if ((fd = open(selinux_virtual_image_context_path(), O_RDONLY)) < 0) {
- virReportSystemError(errno,
- _("cannot open SELinux virtual image context file
%s"),
- selinux_virtual_image_context_path());
- return -1;
- }
+ ptr = strchrnul(data->domain_context, '\n');
+ if (ptr)
+ *ptr = '\0';
- if (saferead(fd, default_image_context, sizeof(default_image_context)) < 0) {
+ if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT,
&(data->file_context)) < 0) {
virReportSystemError(errno,
_("cannot read SELinux virtual image context file
%s"),
selinux_virtual_image_context_path());
- VIR_FORCE_CLOSE(fd);
- return -1;
+ goto error;
}
- VIR_FORCE_CLOSE(fd);
- ptr = strchrnul(default_image_context, '\n');
- if (*ptr == '\n') {
+ ptr = strchrnul(data->file_context, '\n');
+ if (ptr && *ptr == '\n') {
*ptr = '\0';
- strcpy(default_content_context, ptr+1);
- ptr = strchrnul(default_content_context, '\n');
- if (*ptr == '\n')
+ data->content_context = strdup(ptr+1);
+ if (!data->content_context)
+ goto error;
+ ptr = strchrnul(data->content_context, '\n');
+ if (ptr && *ptr == '\n')
*ptr = '\0';
}
+
return 0;
+
+error:
+ VIR_FREE(data->domain_context);
+ VIR_FREE(data->file_context);
+ VIR_FREE(data->content_context);
+ return -1;
}
static int
-SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def)
{
int rc = -1;
@@ -172,7 +181,9 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
int c2 = 0;
context_t ctx = NULL;
const char *range;
+ virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
+ VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
!def->seclabel.baselabel &&
def->seclabel.model) {
@@ -202,6 +213,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
return rc;
}
+ VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type);
+
switch (def->seclabel.type) {
case VIR_DOMAIN_SECLABEL_STATIC:
if (!(ctx = context_new(def->seclabel.label)) ) {
@@ -245,7 +258,7 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
def->seclabel.label =
SELinuxGenNewContext(def->seclabel.baselabel ?
def->seclabel.baselabel :
- default_domain_context, mcs);
+ data->domain_context, mcs);
if (! def->seclabel.label) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot generate selinux context for %s"),
mcs);
@@ -264,13 +277,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
goto cleanup;
}
- if (!def->seclabel.norelabel) {
- def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
- if (!def->seclabel.imagelabel) {
- virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
- _("cannot generate selinux context for %s"),
mcs);
- goto cleanup;
- }
+ def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs);
+ if (!def->seclabel.imagelabel) {
+ virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot generate selinux context for %s"),
mcs);
+ goto cleanup;
}
if (!def->seclabel.model &&
@@ -344,22 +355,39 @@ err:
}
-
static int
-SELinuxSecurityDriverProbe(const char *virtDriver ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverProbe(const char *virtDriver)
{
- return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
+ if (!is_selinux_enabled())
+ return SECURITY_DRIVER_DISABLE;
+
+ if (virtDriver && STREQ(virtDriver, "LXC") &&
+ !virFileExists(selinux_lxc_contexts_path()))
+ return SECURITY_DRIVER_DISABLE;
+
+ return SECURITY_DRIVER_ENABLE;
}
+
static int
-SELinuxSecurityDriverOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
{
- return SELinuxInitialize();
+ return SELinuxInitialize(mgr);
}
+
static int
-SELinuxSecurityDriverClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverClose(virSecurityManagerPtr mgr)
{
+ virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
+
+ if (!data)
+ return 0;
+
+ VIR_FREE(data->domain_context);
+ VIR_FREE(data->file_context);
+ VIR_FREE(data->content_context);
+
return 0;
}
@@ -405,6 +433,7 @@ SELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr
ATTRIBUTE_UNUSED,
strcpy(sec->label, (char *) ctx);
freecon(ctx);
+ VIR_DEBUG("SELinuxGetSecurityProcessLabel %s", sec->label);
sec->enforcing = security_getenforce();
if (sec->enforcing == -1) {
virReportSystemError(errno, "%s",
@@ -639,8 +668,10 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
size_t depth,
void *opaque)
{
- const virSecurityLabelDefPtr secdef = opaque;
+ virSecuritySELinuxCallbackDataPtr cbdata = opaque;
+ const virSecurityLabelDefPtr secdef = cbdata->secdef;
int ret;
+ virSecuritySELinuxDataPtr data =
virSecurityManagerGetPrivateData(cbdata->manager);
if (disk->seclabel && disk->seclabel->norelabel)
return 0;
@@ -649,17 +680,18 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
disk->seclabel->label) {
ret = SELinuxSetFilecon(path, disk->seclabel->label);
} else if (depth == 0) {
+
if (disk->shared) {
- ret = SELinuxSetFileconOptional(path, default_image_context);
+ ret = SELinuxSetFileconOptional(path, data->file_context);
} else if (disk->readonly) {
- ret = SELinuxSetFileconOptional(path, default_content_context);
+ ret = SELinuxSetFileconOptional(path, data->content_context);
} else if (secdef->imagelabel) {
ret = SELinuxSetFileconOptional(path, secdef->imagelabel);
} else {
ret = 0;
}
} else {
- ret = SELinuxSetFileconOptional(path, default_content_context);
+ ret = SELinuxSetFileconOptional(path, data->content_context);
}
if (ret == 1 && !disk->seclabel) {
/* If we failed to set a label, but virt_use_nfs let us
@@ -680,10 +712,13 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
virDomainDiskDefPtr disk)
{
- const virSecurityLabelDefPtr secdef = &def->seclabel;
+ virSecuritySELinuxCallbackData cbdata;
+ cbdata.secdef = &def->seclabel;
+ cbdata.manager = mgr;
+
bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
- if (secdef->norelabel)
+ if (cbdata.secdef->norelabel)
return 0;
if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
@@ -700,7 +735,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
true,
-1, -1, /* current process uid:gid */
SELinuxSetSecurityFileLabel,
- secdef);
+ &cbdata);
}
@@ -1119,6 +1154,7 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr,
{
/* TODO: verify DOI */
const virSecurityLabelDefPtr secdef = &def->seclabel;
+ VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label);
if (def->seclabel.label == NULL)
return 0;
@@ -1300,9 +1336,11 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def,
static int
SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
virDomainSmartcardDefPtr dev,
- void *opaque ATTRIBUTE_UNUSED)
+ void *opaque)
{
const char *database;
+ virSecurityManagerPtr mgr = opaque;
+ virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
switch (dev->type) {
case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
@@ -1312,7 +1350,7 @@ SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
database = dev->data.cert.database;
if (!database)
database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
- return SELinuxSetFilecon(database, default_content_context);
+ return SELinuxSetFilecon(database, data->content_context);
case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
return SELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
@@ -1333,6 +1371,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def,
const char *stdin_path)
{
+ virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
const virSecurityLabelDefPtr secdef = &def->seclabel;
int i;
@@ -1368,19 +1407,19 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
if (virDomainSmartcardDefForeach(def,
true,
SELinuxSetSecuritySmartcardCallback,
- NULL) < 0)
+ mgr) < 0)
return -1;
if (def->os.kernel &&
- SELinuxSetFilecon(def->os.kernel, default_content_context) < 0)
+ SELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
return -1;
if (def->os.initrd &&
- SELinuxSetFilecon(def->os.initrd, default_content_context) < 0)
+ SELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
return -1;
if (stdin_path) {
- if (SELinuxSetFilecon(stdin_path, default_content_context) < 0 &&
+ if (SELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
virStorageFileIsSharedFSType(stdin_path,
VIR_STORAGE_FILE_SHFS_NFS) != 1)
return -1;
@@ -1403,7 +1442,7 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
}
virSecurityDriver virSecurityDriverSELinux = {
- 0,
+ sizeof(virSecuritySELinuxData),
SECURITY_SELINUX_NAME,
SELinuxSecurityDriverProbe,
SELinuxSecurityDriverOpen,
--
1.7.10.1