mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
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:
parent
cf36c23bc9
commit
fa5e68ffbf
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user