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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -33,12 +33,30 @@
#include "storage_file.h" #include "storage_file.h"
#include "virfile.h" #include "virfile.h"
#include "virrandom.h" #include "virrandom.h"
#include "util.h"
#include "conf.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY #define VIR_FROM_THIS VIR_FROM_SECURITY
static char default_domain_context[1024]; #define MAX_CONTEXT 1024
static char default_content_context[1024];
static char default_image_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_VOID_DOI "0"
#define SECURITY_SELINUX_NAME "selinux" #define SECURITY_SELINUX_NAME "selinux"
@ -109,60 +127,53 @@ err:
} }
static int static int
SELinuxInitialize(void) SELinuxInitialize(virSecurityManagerPtr mgr)
{ {
char *ptr = NULL; char *ptr;
int fd = 0; virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
fd = open(selinux_virtual_domain_context_path(), O_RDONLY); if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT, &(data->domain_context)) < 0) {
if (fd < 0) {
virReportSystemError(errno, virReportSystemError(errno,
_("cannot open SELinux virtual domain context file '%s'"), _("cannot read SELinux virtual domain context file '%s'"),
selinux_virtual_domain_context_path()); selinux_virtual_domain_context_path());
return -1; goto error;
} }
if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) { ptr = strchrnul(data->domain_context, '\n');
virReportSystemError(errno, if (ptr)
_("cannot read SELinux virtual domain context file %s"), *ptr = '\0';
selinux_virtual_domain_context_path());
VIR_FORCE_CLOSE(fd);
return -1;
}
VIR_FORCE_CLOSE(fd);
ptr = strchrnul(default_domain_context, '\n'); if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) {
*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) {
virReportSystemError(errno, virReportSystemError(errno,
_("cannot read SELinux virtual image context file %s"), _("cannot read SELinux virtual image context file %s"),
selinux_virtual_image_context_path()); selinux_virtual_image_context_path());
VIR_FORCE_CLOSE(fd); goto error;
return -1;
} }
VIR_FORCE_CLOSE(fd);
ptr = strchrnul(default_image_context, '\n'); ptr = strchrnul(data->file_context, '\n');
if (*ptr == '\n') { if (ptr && *ptr == '\n') {
*ptr = '\0'; *ptr = '\0';
strcpy(default_content_context, ptr+1); data->content_context = strdup(ptr+1);
ptr = strchrnul(default_content_context, '\n'); if (!data->content_context) {
if (*ptr == '\n') virReportOOMError();
goto error;
}
ptr = strchrnul(data->content_context, '\n');
if (ptr && *ptr == '\n')
*ptr = '\0'; *ptr = '\0';
} }
return 0; return 0;
error:
VIR_FREE(data->domain_context);
VIR_FREE(data->file_context);
VIR_FREE(data->content_context);
return -1;
} }
static int static int
SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def) virDomainDefPtr def)
{ {
int rc = -1; int rc = -1;
@ -172,7 +183,9 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
int c2 = 0; int c2 = 0;
context_t ctx = NULL; context_t ctx = NULL;
const char *range; const char *range;
virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) && if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
!def->seclabel.baselabel && !def->seclabel.baselabel &&
def->seclabel.model) { def->seclabel.model) {
@ -202,6 +215,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
return rc; return rc;
} }
VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type);
switch (def->seclabel.type) { switch (def->seclabel.type) {
case VIR_DOMAIN_SECLABEL_STATIC: case VIR_DOMAIN_SECLABEL_STATIC:
if (!(ctx = context_new(def->seclabel.label)) ) { if (!(ctx = context_new(def->seclabel.label)) ) {
@ -245,7 +260,7 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
def->seclabel.label = def->seclabel.label =
SELinuxGenNewContext(def->seclabel.baselabel ? SELinuxGenNewContext(def->seclabel.baselabel ?
def->seclabel.baselabel : def->seclabel.baselabel :
default_domain_context, mcs); data->domain_context, mcs);
if (! def->seclabel.label) { if (! def->seclabel.label) {
virSecurityReportError(VIR_ERR_INTERNAL_ERROR, virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot generate selinux context for %s"), mcs); _("cannot generate selinux context for %s"), mcs);
@ -265,7 +280,7 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
} }
if (!def->seclabel.norelabel) { if (!def->seclabel.norelabel) {
def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs); def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs);
if (!def->seclabel.imagelabel) { if (!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);
@ -344,22 +359,39 @@ err:
} }
static int 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 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; return 0;
} }
@ -405,6 +437,7 @@ SELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
strcpy(sec->label, (char *) ctx); strcpy(sec->label, (char *) ctx);
freecon(ctx); freecon(ctx);
VIR_DEBUG("SELinuxGetSecurityProcessLabel %s", sec->label);
sec->enforcing = security_getenforce(); sec->enforcing = security_getenforce();
if (sec->enforcing == -1) { if (sec->enforcing == -1) {
virReportSystemError(errno, "%s", virReportSystemError(errno, "%s",
@ -639,8 +672,10 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
size_t depth, size_t depth,
void *opaque) void *opaque)
{ {
const virSecurityLabelDefPtr secdef = opaque; virSecuritySELinuxCallbackDataPtr cbdata = opaque;
const virSecurityLabelDefPtr secdef = cbdata->secdef;
int ret; int ret;
virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
if (disk->seclabel && disk->seclabel->norelabel) if (disk->seclabel && disk->seclabel->norelabel)
return 0; return 0;
@ -649,17 +684,18 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
disk->seclabel->label) { disk->seclabel->label) {
ret = SELinuxSetFilecon(path, disk->seclabel->label); ret = SELinuxSetFilecon(path, disk->seclabel->label);
} else if (depth == 0) { } else if (depth == 0) {
if (disk->shared) { if (disk->shared) {
ret = SELinuxSetFileconOptional(path, default_image_context); ret = SELinuxSetFileconOptional(path, data->file_context);
} else if (disk->readonly) { } else if (disk->readonly) {
ret = SELinuxSetFileconOptional(path, default_content_context); ret = SELinuxSetFileconOptional(path, data->content_context);
} else if (secdef->imagelabel) { } else if (secdef->imagelabel) {
ret = SELinuxSetFileconOptional(path, secdef->imagelabel); ret = SELinuxSetFileconOptional(path, secdef->imagelabel);
} else { } else {
ret = 0; ret = 0;
} }
} else { } else {
ret = SELinuxSetFileconOptional(path, default_content_context); ret = SELinuxSetFileconOptional(path, data->content_context);
} }
if (ret == 1 && !disk->seclabel) { if (ret == 1 && !disk->seclabel) {
/* If we failed to set a label, but virt_use_nfs let us /* If we failed to set a label, but virt_use_nfs let us
@ -680,10 +716,13 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
virDomainDiskDefPtr disk) virDomainDiskDefPtr disk)
{ {
const virSecurityLabelDefPtr secdef = &def->seclabel; virSecuritySELinuxCallbackData cbdata;
cbdata.secdef = &def->seclabel;
cbdata.manager = mgr;
bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr); bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
if (secdef->norelabel) if (cbdata.secdef->norelabel)
return 0; return 0;
if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
@ -700,7 +739,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
true, true,
-1, -1, /* current process uid:gid */ -1, -1, /* current process uid:gid */
SELinuxSetSecurityFileLabel, SELinuxSetSecurityFileLabel,
secdef); &cbdata);
} }
@ -1119,6 +1158,7 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr,
{ {
/* TODO: verify DOI */ /* TODO: verify DOI */
const virSecurityLabelDefPtr secdef = &def->seclabel; const virSecurityLabelDefPtr secdef = &def->seclabel;
VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label);
if (def->seclabel.label == NULL) if (def->seclabel.label == NULL)
return 0; return 0;
@ -1300,9 +1340,11 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def,
static int static int
SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def, SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
virDomainSmartcardDefPtr dev, virDomainSmartcardDefPtr dev,
void *opaque ATTRIBUTE_UNUSED) void *opaque)
{ {
const char *database; const char *database;
virSecurityManagerPtr mgr = opaque;
virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
switch (dev->type) { switch (dev->type) {
case VIR_DOMAIN_SMARTCARD_TYPE_HOST: case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
@ -1312,7 +1354,7 @@ SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
database = dev->data.cert.database; database = dev->data.cert.database;
if (!database) if (!database)
database = VIR_DOMAIN_SMARTCARD_DEFAULT_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: case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
return SELinuxSetSecurityChardevLabel(def, &dev->data.passthru); return SELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
@ -1333,6 +1375,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def, virDomainDefPtr def,
const char *stdin_path) const char *stdin_path)
{ {
virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
const virSecurityLabelDefPtr secdef = &def->seclabel; const virSecurityLabelDefPtr secdef = &def->seclabel;
int i; int i;
@ -1368,19 +1411,19 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
if (virDomainSmartcardDefForeach(def, if (virDomainSmartcardDefForeach(def,
true, true,
SELinuxSetSecuritySmartcardCallback, SELinuxSetSecuritySmartcardCallback,
NULL) < 0) mgr) < 0)
return -1; return -1;
if (def->os.kernel && if (def->os.kernel &&
SELinuxSetFilecon(def->os.kernel, default_content_context) < 0) SELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
return -1; return -1;
if (def->os.initrd && if (def->os.initrd &&
SELinuxSetFilecon(def->os.initrd, default_content_context) < 0) SELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
return -1; return -1;
if (stdin_path) { if (stdin_path) {
if (SELinuxSetFilecon(stdin_path, default_content_context) < 0 && if (SELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
virStorageFileIsSharedFSType(stdin_path, virStorageFileIsSharedFSType(stdin_path,
VIR_STORAGE_FILE_SHFS_NFS) != 1) VIR_STORAGE_FILE_SHFS_NFS) != 1)
return -1; return -1;
@ -1403,7 +1446,7 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
} }
virSecurityDriver virSecurityDriverSELinux = { virSecurityDriver virSecurityDriverSELinux = {
0, sizeof(virSecuritySELinuxData),
SECURITY_SELINUX_NAME, SECURITY_SELINUX_NAME,
SELinuxSecurityDriverProbe, SELinuxSecurityDriverProbe,
SELinuxSecurityDriverOpen, SELinuxSecurityDriverOpen,