Use private data struct in SELinux driver

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@redhat.com>
This commit is contained in:
Daniel Walsh 2012-05-11 10:43:30 +01:00 committed by Daniel P. Berrange
parent cf36c23bc9
commit fa5e68ffbf

View File

@ -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,53 @@ 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(data->domain_context, '\n');
if (ptr)
*ptr = '\0';
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;
}
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) {
virReportOOMError();
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 +183,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 +215,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 +260,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);
@ -265,7 +280,7 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
}
if (!def->seclabel.norelabel) {
def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs);
if (!def->seclabel.imagelabel) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot generate selinux context for %s"), mcs);
@ -344,22 +359,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)
{
return SELinuxInitialize();
}
static int
SELinuxSecurityDriverClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
SELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
{
return SELinuxInitialize(mgr);
}
static int
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 +437,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 +672,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 +684,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 +716,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 +739,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
true,
-1, -1, /* current process uid:gid */
SELinuxSetSecurityFileLabel,
secdef);
&cbdata);
}
@ -1119,6 +1158,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 +1340,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 +1354,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 +1375,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def,
const char *stdin_path)
{
virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
const virSecurityLabelDefPtr secdef = &def->seclabel;
int i;
@ -1368,19 +1411,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 +1446,7 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
}
virSecurityDriver virSecurityDriverSELinux = {
0,
sizeof(virSecuritySELinuxData),
SECURITY_SELINUX_NAME,
SELinuxSecurityDriverProbe,
SELinuxSecurityDriverOpen,