2010-01-13 16:43:29 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2010 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.
|
|
|
|
*
|
|
|
|
* QEMU POSIX DAC security driver
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include "qemu_security_dac.h"
|
|
|
|
#include "qemu_conf.h"
|
|
|
|
#include "datatypes.h"
|
|
|
|
#include "virterror_internal.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "logging.h"
|
|
|
|
#include "pci.h"
|
|
|
|
#include "hostusb.h"
|
|
|
|
#include "storage_file.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
|
|
|
|
|
|
|
static struct qemud_driver *driver;
|
|
|
|
|
|
|
|
void qemuSecurityDACSetDriver(struct qemud_driver *newdriver)
|
|
|
|
{
|
|
|
|
driver = newdriver;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-04 20:02:58 +00:00
|
|
|
qemuSecurityDACSetOwnership(const char *path, int uid, int gid)
|
2010-01-13 16:43:29 +00:00
|
|
|
{
|
2010-04-21 17:44:43 +00:00
|
|
|
VIR_INFO("Setting DAC user and group on '%s' to '%d:%d'", path, uid, gid);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
if (chown(path, uid, gid) < 0) {
|
|
|
|
struct stat sb;
|
|
|
|
int chown_errno = errno;
|
|
|
|
|
|
|
|
if (stat(path, &sb) >= 0) {
|
|
|
|
if (sb.st_uid == uid &&
|
|
|
|
sb.st_gid == gid) {
|
|
|
|
/* It's alright, there's nothing to change anyway. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chown_errno == EOPNOTSUPP) {
|
2010-04-21 17:44:43 +00:00
|
|
|
VIR_INFO("Setting user and group to '%d:%d' on '%s' not supported by filesystem",
|
2010-01-13 16:43:29 +00:00
|
|
|
uid, gid, path);
|
|
|
|
} else if (chown_errno == EPERM) {
|
2010-04-21 17:44:43 +00:00
|
|
|
VIR_INFO("Setting user and group to '%d:%d' on '%s' not permitted",
|
2010-01-13 16:43:29 +00:00
|
|
|
uid, gid, path);
|
|
|
|
} else if (chown_errno == EROFS) {
|
2010-04-21 17:44:43 +00:00
|
|
|
VIR_INFO("Setting user and group to '%d:%d' on '%s' not possible on readonly filesystem",
|
2010-01-13 16:43:29 +00:00
|
|
|
uid, gid, path);
|
|
|
|
} else {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(chown_errno,
|
2010-04-21 17:44:43 +00:00
|
|
|
_("unable to set user and group to '%d:%d' on '%s'"),
|
2010-01-13 16:43:29 +00:00
|
|
|
uid, gid, path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2010-02-04 20:02:58 +00:00
|
|
|
qemuSecurityDACRestoreSecurityFileLabel(const char *path)
|
2010-01-13 16:43:29 +00:00
|
|
|
{
|
|
|
|
struct stat buf;
|
|
|
|
int rc = -1;
|
|
|
|
char *newpath = NULL;
|
|
|
|
|
2010-04-21 17:44:43 +00:00
|
|
|
VIR_INFO("Restoring DAC user and group on '%s'", path);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
2010-05-14 20:50:27 +00:00
|
|
|
if (virFileResolveLink(path, &newpath) < 0) {
|
|
|
|
virReportSystemError(errno,
|
2010-01-13 16:43:29 +00:00
|
|
|
_("cannot resolve symlink %s"), path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(newpath, &buf) != 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* XXX record previous ownership */
|
2010-02-04 20:02:58 +00:00
|
|
|
rc = qemuSecurityDACSetOwnership(newpath, 0, 0);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
err:
|
|
|
|
VIR_FREE(newpath);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACSetSecurityImageLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
|
|
|
|
{
|
|
|
|
const char *path;
|
|
|
|
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!disk->src)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
path = disk->src;
|
|
|
|
do {
|
|
|
|
virStorageFileMetadata meta;
|
|
|
|
int ret;
|
|
|
|
|
2010-02-04 22:46:55 +00:00
|
|
|
ret = virStorageFileGetMetadata(path, &meta);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
if (path != disk->src)
|
|
|
|
VIR_FREE(path);
|
|
|
|
path = NULL;
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (meta.backingStore != NULL &&
|
2010-02-04 20:02:58 +00:00
|
|
|
qemuSecurityDACSetOwnership(meta.backingStore,
|
|
|
|
driver->user, driver->group) < 0) {
|
2010-01-13 16:43:29 +00:00
|
|
|
VIR_FREE(meta.backingStore);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
path = meta.backingStore;
|
|
|
|
} while (path != NULL);
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACSetOwnership(disk->src, driver->user, driver->group);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
qemuSecurityDACRestoreSecurityImageLabelInt(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
|
|
|
virDomainDiskDefPtr disk,
|
|
|
|
int migrated)
|
2010-01-13 16:43:29 +00:00
|
|
|
{
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Don't restore labels on readoly/shared disks, because
|
|
|
|
* other VMs may still be accessing these
|
|
|
|
* Alternatively we could iterate over all running
|
|
|
|
* domains and try to figure out if it is in use, but
|
|
|
|
* this would not work for clustered filesystems, since
|
|
|
|
* we can't see running VMs using the file on other nodes
|
|
|
|
* Safest bet is thus to skip the restore step.
|
|
|
|
*/
|
|
|
|
if (disk->readonly || disk->shared)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!disk->src)
|
|
|
|
return 0;
|
|
|
|
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
/* If we have a shared FS & doing migrated, we must not
|
|
|
|
* change ownership, because that kills access on the
|
|
|
|
* destination host which is sub-optimal for the guest
|
|
|
|
* VM's I/O attempts :-)
|
|
|
|
*/
|
|
|
|
if (migrated) {
|
|
|
|
int rc = virStorageFileIsSharedFS(disk->src);
|
|
|
|
if (rc < 0)
|
|
|
|
return -1;
|
|
|
|
if (rc == 1) {
|
|
|
|
VIR_DEBUG("Skipping image label restore on %s because FS is shared",
|
|
|
|
disk->src);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACRestoreSecurityFileLabel(disk->src);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
static int
|
|
|
|
qemuSecurityDACRestoreSecurityImageLabel(virDomainObjPtr vm,
|
|
|
|
virDomainDiskDefPtr disk)
|
|
|
|
{
|
|
|
|
return qemuSecurityDACRestoreSecurityImageLabelInt(vm, disk, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-13 16:43:29 +00:00
|
|
|
static int
|
2010-02-10 09:55:39 +00:00
|
|
|
qemuSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *file,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACSetOwnership(file, driver->user, driver->group);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 09:55:39 +00:00
|
|
|
qemuSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *file,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACSetOwnership(file, driver->user, driver->group);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACSetSecurityHostdevLabel(virDomainObjPtr vm,
|
2010-01-13 16:43:29 +00:00
|
|
|
virDomainHostdevDefPtr dev)
|
|
|
|
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (dev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
|
2010-02-04 23:25:16 +00:00
|
|
|
usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
|
2010-03-04 11:48:16 +00:00
|
|
|
dev->source.subsys.u.usb.device);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
if (!usb)
|
|
|
|
goto done;
|
|
|
|
|
2010-02-10 09:55:39 +00:00
|
|
|
ret = usbDeviceFileIterate(usb, qemuSecurityDACSetSecurityUSBLabel, vm);
|
2010-02-04 23:25:16 +00:00
|
|
|
usbFreeDevice(usb);
|
2010-01-13 16:43:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
|
2010-02-04 23:16:34 +00:00
|
|
|
pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
|
2010-01-13 16:43:29 +00:00
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function);
|
|
|
|
|
|
|
|
if (!pci)
|
|
|
|
goto done;
|
|
|
|
|
2010-02-10 09:55:39 +00:00
|
|
|
ret = pciDeviceFileIterate(pci, qemuSecurityDACSetSecurityPCILabel, vm);
|
2010-02-04 23:16:34 +00:00
|
|
|
pciFreeDevice(pci);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 09:55:39 +00:00
|
|
|
qemuSecurityDACRestoreSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *file,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACRestoreSecurityFileLabel(file);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 09:55:39 +00:00
|
|
|
qemuSecurityDACRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *file,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACRestoreSecurityFileLabel(file);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACRestoreSecurityHostdevLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
virDomainHostdevDefPtr dev)
|
|
|
|
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (dev->source.subsys.type) {
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
|
2010-02-04 23:25:16 +00:00
|
|
|
usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
|
2010-03-04 11:48:16 +00:00
|
|
|
dev->source.subsys.u.usb.device);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
if (!usb)
|
|
|
|
goto done;
|
|
|
|
|
2010-02-10 09:55:39 +00:00
|
|
|
ret = usbDeviceFileIterate(usb, qemuSecurityDACRestoreSecurityUSBLabel, NULL);
|
2010-02-04 23:25:16 +00:00
|
|
|
usbFreeDevice(usb);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
|
2010-02-04 23:16:34 +00:00
|
|
|
pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
|
2010-01-13 16:43:29 +00:00
|
|
|
dev->source.subsys.u.pci.bus,
|
|
|
|
dev->source.subsys.u.pci.slot,
|
|
|
|
dev->source.subsys.u.pci.function);
|
|
|
|
|
|
|
|
if (!pci)
|
|
|
|
goto done;
|
|
|
|
|
2010-02-10 09:55:39 +00:00
|
|
|
ret = pciDeviceFileIterate(pci, qemuSecurityDACRestoreSecurityPCILabel, NULL);
|
2010-02-04 23:16:34 +00:00
|
|
|
pciFreeDevice(pci);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
|
|
|
|
int migrated)
|
2010-01-13 16:43:29 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
VIR_DEBUG("Restoring security label on %s migrated=%d",
|
|
|
|
vm->def->name, migrated);
|
2010-01-13 16:43:29 +00:00
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
2010-02-09 19:18:21 +00:00
|
|
|
if (qemuSecurityDACRestoreSecurityHostdevLabel(vm,
|
2010-01-13 16:43:29 +00:00
|
|
|
vm->def->hostdevs[i]) < 0)
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
Don't reset user/group/security label on shared filesystems during migrate
When QEMU runs with its disk on NFS, and as a non-root user, the
disk is chownd to that non-root user. When migration completes
the last step is shutting down the QEMU on the source host. THis
normally resets user/group/security label. This is bad when the
VM was just migrated because the file is still in use on the dest
host. It is thus neccessary to skip the reset step for any files
found to be on a shared filesystem
* src/libvirt_private.syms: Export virStorageFileIsSharedFS
* src/util/storage_file.c, src/util/storage_file.h: Add a new
method virStorageFileIsSharedFS() to determine if a file is
on a shared filesystem (NFS, GFS, OCFS2, etc)
* src/qemu/qemu_driver.c: Tell security driver not to reset
disk labels on migration completion
* src/qemu/qemu_security_dac.c, src/qemu/qemu_security_stacked.c,
src/security/security_selinux.c, src/security/security_driver.h,
src/security/security_apparmor.c: Add ability to skip disk
restore step for files on shared filesystems.
2010-05-13 15:49:22 +00:00
|
|
|
if (qemuSecurityDACRestoreSecurityImageLabelInt(vm,
|
|
|
|
vm->def->disks[i],
|
|
|
|
migrated) < 0)
|
2010-01-13 16:43:29 +00:00
|
|
|
rc = -1;
|
|
|
|
}
|
2010-03-12 18:38:39 +00:00
|
|
|
|
|
|
|
if (vm->def->os.kernel &&
|
|
|
|
qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
|
|
|
|
rc = -1;
|
|
|
|
|
|
|
|
if (vm->def->os.initrd &&
|
|
|
|
qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.initrd) < 0)
|
|
|
|
rc = -1;
|
|
|
|
|
2010-01-13 16:43:29 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-06-04 16:20:29 +00:00
|
|
|
qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
|
2010-01-13 16:43:29 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!driver->privileged || !driver->dynamicOwnership)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
|
|
|
/* XXX fixme - we need to recursively label the entriy tree :-( */
|
|
|
|
if (vm->def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR)
|
|
|
|
continue;
|
2010-02-09 19:18:21 +00:00
|
|
|
if (qemuSecurityDACSetSecurityImageLabel(vm, vm->def->disks[i]) < 0)
|
2010-01-13 16:43:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
2010-02-09 19:18:21 +00:00
|
|
|
if (qemuSecurityDACSetSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0)
|
2010-01-13 16:43:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-03-12 18:38:39 +00:00
|
|
|
if (vm->def->os.kernel &&
|
|
|
|
qemuSecurityDACSetOwnership(vm->def->os.kernel,
|
|
|
|
driver->user,
|
|
|
|
driver->group) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (vm->def->os.initrd &&
|
|
|
|
qemuSecurityDACSetOwnership(vm->def->os.initrd,
|
|
|
|
driver->user,
|
|
|
|
driver->group) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2010-01-13 16:43:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACSetSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *savefile)
|
|
|
|
{
|
2010-05-13 17:30:33 +00:00
|
|
|
if (!driver->privileged)
|
2010-01-13 16:43:29 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACSetOwnership(savefile, driver->user, driver->group);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACRestoreSavedStateLabel(virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
const char *savefile)
|
|
|
|
{
|
2010-05-13 17:30:33 +00:00
|
|
|
if (!driver->privileged)
|
2010-01-13 16:43:29 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-02-04 20:02:58 +00:00
|
|
|
return qemuSecurityDACRestoreSecurityFileLabel(savefile);
|
2010-01-13 16:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-09 19:18:21 +00:00
|
|
|
qemuSecurityDACSetProcessLabel(virSecurityDriverPtr drv ATTRIBUTE_UNUSED,
|
2010-01-13 16:43:29 +00:00
|
|
|
virDomainObjPtr vm ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
DEBUG("Dropping privileges of VM to %d:%d", driver->user, driver->group);
|
|
|
|
|
|
|
|
if (!driver->privileged)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (driver->group) {
|
|
|
|
if (setregid(driver->group, driver->group) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-13 16:43:29 +00:00
|
|
|
_("cannot change to '%d' group"),
|
|
|
|
driver->group);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (driver->user) {
|
|
|
|
if (setreuid(driver->user, driver->user) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2010-01-13 16:43:29 +00:00
|
|
|
_("cannot change to '%d' user"),
|
|
|
|
driver->user);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-13 17:06:57 +00:00
|
|
|
virSecurityDriver qemuDACSecurityDriver = {
|
2010-01-13 16:43:29 +00:00
|
|
|
.name = "qemuDAC",
|
|
|
|
|
|
|
|
.domainSetSecurityProcessLabel = qemuSecurityDACSetProcessLabel,
|
|
|
|
|
|
|
|
.domainSetSecurityImageLabel = qemuSecurityDACSetSecurityImageLabel,
|
|
|
|
.domainRestoreSecurityImageLabel = qemuSecurityDACRestoreSecurityImageLabel,
|
|
|
|
|
|
|
|
.domainSetSecurityAllLabel = qemuSecurityDACSetSecurityAllLabel,
|
|
|
|
.domainRestoreSecurityAllLabel = qemuSecurityDACRestoreSecurityAllLabel,
|
|
|
|
|
|
|
|
.domainSetSecurityHostdevLabel = qemuSecurityDACSetSecurityHostdevLabel,
|
|
|
|
.domainRestoreSecurityHostdevLabel = qemuSecurityDACRestoreSecurityHostdevLabel,
|
|
|
|
|
|
|
|
.domainSetSavedStateLabel = qemuSecurityDACSetSavedStateLabel,
|
|
|
|
.domainRestoreSavedStateLabel = qemuSecurityDACRestoreSavedStateLabel,
|
|
|
|
};
|