mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-24 00:20:53 +00:00
88bd1a644b
When a qemu domain is backed by huge pages, apparmor needs to grant the domain rw access to files under the hugetlbfs mount point. Add a hook, called in qemu_process.c, which ends up adding the read-write access through virt-aa-helper. Qemu will be creating a randomly named file under the mountpoint and unlinking it as soon as it has mmap()d it, therefore we cannot predict the full pathname, but for the same reason it is generally safe to provide access to $path/**. Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
552 lines
15 KiB
C
552 lines
15 KiB
C
/*
|
|
* Copyright (C) 2010-2011 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
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Stacked security driver
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "security_stack.h"
|
|
|
|
#include "virterror_internal.h"
|
|
#include "memory.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_SECURITY
|
|
|
|
typedef struct _virSecurityStackData virSecurityStackData;
|
|
typedef virSecurityStackData *virSecurityStackDataPtr;
|
|
typedef struct _virSecurityStackItem virSecurityStackItem;
|
|
typedef virSecurityStackItem* virSecurityStackItemPtr;
|
|
|
|
struct _virSecurityStackItem {
|
|
virSecurityManagerPtr securityManager;
|
|
virSecurityStackItemPtr next;
|
|
};
|
|
|
|
struct _virSecurityStackData {
|
|
virSecurityStackItemPtr itemsHead;
|
|
};
|
|
|
|
int
|
|
virSecurityStackAddNested(virSecurityManagerPtr mgr,
|
|
virSecurityManagerPtr nested)
|
|
{
|
|
virSecurityStackItemPtr item = NULL;
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr tmp;
|
|
|
|
tmp = priv->itemsHead;
|
|
while (tmp && tmp->next)
|
|
tmp = tmp->next;
|
|
|
|
if (VIR_ALLOC(item) < 0) {
|
|
virReportOOMError();
|
|
return -1;
|
|
}
|
|
item->securityManager = nested;
|
|
if (tmp)
|
|
tmp->next = item;
|
|
else
|
|
priv->itemsHead = item;
|
|
|
|
return 0;
|
|
}
|
|
|
|
virSecurityManagerPtr
|
|
virSecurityStackGetPrimary(virSecurityManagerPtr mgr)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
return priv->itemsHead->securityManager;
|
|
}
|
|
|
|
static virSecurityDriverStatus
|
|
virSecurityStackProbe(const char *virtDriver ATTRIBUTE_UNUSED)
|
|
{
|
|
return SECURITY_DRIVER_ENABLE;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackClose(virSecurityManagerPtr mgr)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr next, item = priv->itemsHead;
|
|
|
|
while (item) {
|
|
next = item->next;
|
|
virSecurityManagerFree(item->securityManager);
|
|
VIR_FREE(item);
|
|
item = next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const char *
|
|
virSecurityStackGetModel(virSecurityManagerPtr mgr)
|
|
{
|
|
return virSecurityManagerGetModel(virSecurityStackGetPrimary(mgr));
|
|
}
|
|
|
|
static const char *
|
|
virSecurityStackGetDOI(virSecurityManagerPtr mgr)
|
|
{
|
|
return virSecurityManagerGetDOI(virSecurityStackGetPrimary(mgr));
|
|
}
|
|
|
|
static int
|
|
virSecurityStackVerify(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr def)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerVerify(item->securityManager, def) < 0) {
|
|
rc = -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackGenLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (virSecurityManagerGenLabel(virSecurityStackGetPrimary(mgr), vm) < 0)
|
|
rc = -1;
|
|
|
|
// TODO
|
|
#if 0
|
|
/* We don't allow secondary drivers to generate labels.
|
|
* This may have to change in the future, but requires
|
|
* changes elsewhere in domain_conf.c and capabilities.c
|
|
* XML formats first, to allow recording of multiple
|
|
* labels
|
|
*/
|
|
if (virSecurityManagerGenLabel(priv->secondary, vm) < 0)
|
|
rc = -1;
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackReleaseLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (virSecurityManagerReleaseLabel(virSecurityStackGetPrimary(mgr), vm) < 0)
|
|
rc = -1;
|
|
|
|
// TODO
|
|
#if 0
|
|
/* XXX See note in GenLabel */
|
|
if (virSecurityManagerReleaseLabel(priv->secondary, vm) < 0)
|
|
rc = -1;
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackReserveLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
pid_t pid)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (virSecurityManagerReserveLabel(virSecurityStackGetPrimary(mgr), vm, pid) < 0)
|
|
rc = -1;
|
|
// TODO
|
|
#if 0
|
|
/* XXX See note in GenLabel */
|
|
if (virSecurityManagerReserveLabel(priv->secondary, vm, pid) < 0)
|
|
rc = -1;
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
virDomainDiskDefPtr disk)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetImageLabel(item->securityManager, vm, disk) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
virDomainDiskDefPtr disk)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerRestoreImageLabel(item->securityManager, vm, disk) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
virDomainHostdevDefPtr dev)
|
|
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetHostdevLabel(item->securityManager, vm, dev) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
virDomainHostdevDefPtr dev)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerRestoreHostdevLabel(item->securityManager, vm, dev) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
const char *stdin_path)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetAllLabel(item->securityManager, vm, stdin_path) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
int migrated)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerRestoreAllLabel(item->securityManager, vm, migrated) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetSavedStateLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
const char *savefile)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetSavedStateLabel(item->securityManager, vm, savefile) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackRestoreSavedStateLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
const char *savefile)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerRestoreSavedStateLabel(item->securityManager, vm, savefile) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetProcessLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetProcessLabel(item->securityManager, vm) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackGetProcessLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
pid_t pid,
|
|
virSecurityLabelPtr seclabel)
|
|
{
|
|
int rc = 0;
|
|
|
|
// TODO
|
|
#if 0
|
|
if (virSecurityManagerGetProcessLabel(priv->secondary, vm, pid, seclabel) < 0)
|
|
rc = -1;
|
|
#endif
|
|
if (virSecurityManagerGetProcessLabel(virSecurityStackGetPrimary(mgr), vm, pid, seclabel) < 0)
|
|
rc = -1;
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetDaemonSocketLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetDaemonSocketLabel(item->securityManager, vm) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackSetSocketLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetSocketLabel(item->securityManager, vm) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
virSecurityStackClearSocketLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerClearSocketLabel(item->securityManager, vm) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
int fd)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetImageFDLabel(item->securityManager, vm, fd) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackSetTapFDLabel(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
int fd)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetTapFDLabel(item->securityManager, vm, fd) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
virSecurityStackSetHugepages(virSecurityManagerPtr mgr,
|
|
virDomainDefPtr vm,
|
|
const char *path)
|
|
{
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item = priv->itemsHead;
|
|
int rc = 0;
|
|
|
|
for (; item; item = item->next) {
|
|
if (virSecurityManagerSetHugepages(item->securityManager, vm, path) < 0)
|
|
rc = -1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static char *virSecurityStackGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
|
|
virDomainDefPtr vm ATTRIBUTE_UNUSED) {
|
|
return NULL;
|
|
}
|
|
|
|
virSecurityManagerPtr*
|
|
virSecurityStackGetNested(virSecurityManagerPtr mgr)
|
|
{
|
|
virSecurityManagerPtr *list = NULL;
|
|
virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
|
|
virSecurityStackItemPtr item;
|
|
int len = 0, i = 0;
|
|
|
|
for (item = priv->itemsHead; item; item = item->next)
|
|
len++;
|
|
|
|
if (VIR_ALLOC_N(list, len + 1) < 0) {
|
|
virReportOOMError();
|
|
return NULL;
|
|
}
|
|
|
|
for (item = priv->itemsHead; item; item = item->next, i++)
|
|
list[i] = item->securityManager;
|
|
list[len] = NULL;
|
|
|
|
return list;
|
|
}
|
|
|
|
virSecurityDriver virSecurityDriverStack = {
|
|
.privateDataLen = sizeof(virSecurityStackData),
|
|
.name = "stack",
|
|
.probe = virSecurityStackProbe,
|
|
.open = virSecurityStackOpen,
|
|
.close = virSecurityStackClose,
|
|
|
|
.getModel = virSecurityStackGetModel,
|
|
.getDOI = virSecurityStackGetDOI,
|
|
|
|
.domainSecurityVerify = virSecurityStackVerify,
|
|
|
|
.domainSetSecurityImageLabel = virSecurityStackSetSecurityImageLabel,
|
|
.domainRestoreSecurityImageLabel = virSecurityStackRestoreSecurityImageLabel,
|
|
|
|
.domainSetSecurityDaemonSocketLabel = virSecurityStackSetDaemonSocketLabel,
|
|
.domainSetSecuritySocketLabel = virSecurityStackSetSocketLabel,
|
|
.domainClearSecuritySocketLabel = virSecurityStackClearSocketLabel,
|
|
|
|
.domainGenSecurityLabel = virSecurityStackGenLabel,
|
|
.domainReserveSecurityLabel = virSecurityStackReserveLabel,
|
|
.domainReleaseSecurityLabel = virSecurityStackReleaseLabel,
|
|
|
|
.domainGetSecurityProcessLabel = virSecurityStackGetProcessLabel,
|
|
.domainSetSecurityProcessLabel = virSecurityStackSetProcessLabel,
|
|
|
|
.domainSetSecurityAllLabel = virSecurityStackSetSecurityAllLabel,
|
|
.domainRestoreSecurityAllLabel = virSecurityStackRestoreSecurityAllLabel,
|
|
|
|
.domainSetSecurityHostdevLabel = virSecurityStackSetSecurityHostdevLabel,
|
|
.domainRestoreSecurityHostdevLabel = virSecurityStackRestoreSecurityHostdevLabel,
|
|
|
|
.domainSetSavedStateLabel = virSecurityStackSetSavedStateLabel,
|
|
.domainRestoreSavedStateLabel = virSecurityStackRestoreSavedStateLabel,
|
|
|
|
.domainSetSecurityImageFDLabel = virSecurityStackSetImageFDLabel,
|
|
.domainSetSecurityTapFDLabel = virSecurityStackSetTapFDLabel,
|
|
|
|
.domainGetSecurityMountOptions = virSecurityStackGetMountOptions,
|
|
|
|
.domainSetSecurityHugepages = virSecurityStackSetHugepages,
|
|
};
|