mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
Support relabelling of USB and PCI devices
* src/security.h: Driver API for relabelling host devices * src/security_selinux.c: Implement relabelling of PCI and USB devices * src/qemu_driver.c: Relabel USB/PCI devices before hotplug
This commit is contained in:
parent
c42c1b8a5e
commit
0e9ae444bd
@ -5634,6 +5634,9 @@ static int qemudDomainAttachHostDevice(virConnectPtr conn,
|
||||
|
||||
if (qemuDomainSetDeviceOwnership(conn, driver, dev, 0) < 0)
|
||||
return -1;
|
||||
if (driver->securityDriver &&
|
||||
driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
|
||||
return -1;
|
||||
|
||||
switch (hostdev->source.subsys.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
||||
@ -5702,9 +5705,6 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
}
|
||||
}
|
||||
|
||||
if (driver->securityDriver)
|
||||
driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
|
||||
|
||||
switch (dev->data.disk->device) {
|
||||
case VIR_DOMAIN_DISK_DEVICE_CDROM:
|
||||
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
|
||||
@ -6104,8 +6104,12 @@ static int qemudDomainDetachHostDevice(virConnectPtr conn,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (driver->securityDriver &&
|
||||
driver->securityDriver->domainSetSecurityHostdevLabel(conn, vm, dev->data.hostdev) < 0)
|
||||
VIR_WARN0("Failed to restore device labelling");
|
||||
|
||||
if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
|
||||
VIR_WARN0("Fail to restore disk device ownership");
|
||||
VIR_WARN0("Failed to restore device ownership");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -36,6 +36,11 @@ typedef int (*virSecurityDomainRestoreImageLabel) (virConnectPtr conn,
|
||||
typedef int (*virSecurityDomainSetImageLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virDomainDiskDefPtr disk);
|
||||
typedef int (*virSecurityDomainRestoreHostdevLabel) (virConnectPtr conn,
|
||||
virDomainHostdevDefPtr dev);
|
||||
typedef int (*virSecurityDomainSetHostdevLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virDomainHostdevDefPtr dev);
|
||||
typedef int (*virSecurityDomainGenLabel) (virConnectPtr conn,
|
||||
virDomainObjPtr sec);
|
||||
typedef int (*virSecurityDomainReserveLabel) (virConnectPtr conn,
|
||||
@ -63,6 +68,8 @@ struct _virSecurityDriver {
|
||||
virSecurityDomainGetLabel domainGetSecurityLabel;
|
||||
virSecurityDomainSetLabel domainSetSecurityLabel;
|
||||
virSecurityDomainRestoreLabel domainRestoreSecurityLabel;
|
||||
virSecurityDomainRestoreHostdevLabel domainRestoreSecurityHostdevLabel;
|
||||
virSecurityDomainSetHostdevLabel domainSetSecurityHostdevLabel;
|
||||
|
||||
/*
|
||||
* This is internally managed driver state and should only be accessed
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "logging.h"
|
||||
#include "pci.h"
|
||||
#include "hostusb.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_SECURITY
|
||||
|
||||
@ -335,8 +337,10 @@ SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon)
|
||||
}
|
||||
|
||||
/* if the error complaint is related to an image hosted on
|
||||
* an nfs mount, then ignore it.
|
||||
* rhbz 517157
|
||||
* an nfs mount, or a usbfs/sysfs filesystem not supporting
|
||||
* labelling, then just ignore it & hope for the best.
|
||||
* The user hopefully set one of the neccessary SELinux
|
||||
* virt_use_{nfs,usb,pci} boolean tunables to allow it...
|
||||
*/
|
||||
if (setfilecon_errno != EOPNOTSUPP) {
|
||||
virSecurityReportError(conn, VIR_ERR_ERROR,
|
||||
@ -353,26 +357,14 @@ SELinuxSetFilecon(virConnectPtr conn, const char *path, char *tcon)
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityImageLabel(virConnectPtr conn,
|
||||
virDomainDiskDefPtr disk)
|
||||
SELinuxRestoreSecurityFileLabel(virConnectPtr conn,
|
||||
const char *path)
|
||||
{
|
||||
struct stat buf;
|
||||
security_context_t fcon = NULL;
|
||||
int rc = -1;
|
||||
int err;
|
||||
char *newpath = NULL;
|
||||
const char *path = disk->src;
|
||||
|
||||
/* 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 ((err = virFileResolveLink(path, &newpath)) < 0) {
|
||||
virReportSystemError(conn, err,
|
||||
@ -392,6 +384,27 @@ err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityImageLabel(virConnectPtr conn,
|
||||
virDomainDiskDefPtr disk)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
return SELinuxRestoreSecurityFileLabel(conn, disk->src);
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxSetSecurityImageLabel(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
@ -414,6 +427,153 @@ SELinuxSetSecurityImageLabel(virConnectPtr conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
SELinuxSetSecurityPCILabel(virConnectPtr conn,
|
||||
pciDevice *dev ATTRIBUTE_UNUSED,
|
||||
const char *file, void *opaque)
|
||||
{
|
||||
virDomainObjPtr vm = opaque;
|
||||
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
|
||||
|
||||
return SELinuxSetFilecon(conn, file, secdef->imagelabel);
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxSetSecurityUSBLabel(virConnectPtr conn,
|
||||
usbDevice *dev ATTRIBUTE_UNUSED,
|
||||
const char *file, void *opaque)
|
||||
{
|
||||
virDomainObjPtr vm = opaque;
|
||||
const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
|
||||
|
||||
return SELinuxSetFilecon(conn, file, secdef->imagelabel);
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxSetSecurityHostdevLabel(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
virDomainHostdevDefPtr dev)
|
||||
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
return 0;
|
||||
|
||||
switch (dev->source.subsys.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
|
||||
if (dev->source.subsys.u.usb.bus && dev->source.subsys.u.usb.device) {
|
||||
usbDevice *usb = usbGetDevice(conn,
|
||||
dev->source.subsys.u.usb.bus,
|
||||
dev->source.subsys.u.usb.device);
|
||||
|
||||
if (!usb)
|
||||
goto done;
|
||||
|
||||
ret = usbDeviceFileIterate(conn, usb, SELinuxSetSecurityUSBLabel, vm);
|
||||
usbFreeDevice(conn, usb);
|
||||
|
||||
break;
|
||||
} else {
|
||||
/* XXX deal with product/vendor better */
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
|
||||
pciDevice *pci = pciGetDevice(conn,
|
||||
dev->source.subsys.u.pci.domain,
|
||||
dev->source.subsys.u.pci.bus,
|
||||
dev->source.subsys.u.pci.slot,
|
||||
dev->source.subsys.u.pci.function);
|
||||
|
||||
if (!pci)
|
||||
goto done;
|
||||
|
||||
ret = pciDeviceFileIterate(conn, pci, SELinuxSetSecurityPCILabel, vm);
|
||||
pciFreeDevice(conn, pci);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityPCILabel(virConnectPtr conn,
|
||||
pciDevice *dev ATTRIBUTE_UNUSED,
|
||||
const char *file,
|
||||
void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return SELinuxRestoreSecurityFileLabel(conn, file);
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityUSBLabel(virConnectPtr conn,
|
||||
usbDevice *dev ATTRIBUTE_UNUSED,
|
||||
const char *file,
|
||||
void *opaque ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return SELinuxRestoreSecurityFileLabel(conn, file);
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityHostdevLabel(virConnectPtr conn,
|
||||
virDomainHostdevDefPtr dev)
|
||||
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
return 0;
|
||||
|
||||
switch (dev->source.subsys.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
|
||||
usbDevice *usb = usbGetDevice(conn,
|
||||
dev->source.subsys.u.usb.bus,
|
||||
dev->source.subsys.u.usb.device);
|
||||
|
||||
if (!usb)
|
||||
goto done;
|
||||
|
||||
ret = usbDeviceFileIterate(conn, usb, SELinuxRestoreSecurityUSBLabel, NULL);
|
||||
usbFreeDevice(conn, usb);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
|
||||
pciDevice *pci = pciGetDevice(conn,
|
||||
dev->source.subsys.u.pci.domain,
|
||||
dev->source.subsys.u.pci.bus,
|
||||
dev->source.subsys.u.pci.slot,
|
||||
dev->source.subsys.u.pci.function);
|
||||
|
||||
if (!pci)
|
||||
goto done;
|
||||
|
||||
ret = pciDeviceFileIterate(conn, pci, SELinuxRestoreSecurityPCILabel, NULL);
|
||||
pciFreeDevice(conn, pci);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
SELinuxRestoreSecurityLabel(virConnectPtr conn,
|
||||
virDomainObjPtr vm)
|
||||
@ -422,6 +582,10 @@ SELinuxRestoreSecurityLabel(virConnectPtr conn,
|
||||
int i;
|
||||
int rc = 0;
|
||||
if (secdef->imagelabel) {
|
||||
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
||||
if (SELinuxRestoreSecurityHostdevLabel(conn, vm->def->hostdevs[i]) < 0)
|
||||
rc = -1;
|
||||
}
|
||||
for (i = 0 ; i < vm->def->ndisks ; i++) {
|
||||
if (SELinuxRestoreSecurityImageLabel(conn, vm->def->disks[i]) < 0)
|
||||
rc = -1;
|
||||
@ -486,6 +650,10 @@ SELinuxSetSecurityLabel(virConnectPtr conn,
|
||||
if (SELinuxSetSecurityImageLabel(conn, vm, vm->def->disks[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
||||
if (SELinuxSetSecurityHostdevLabel(conn, vm, vm->def->hostdevs[i]) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -503,4 +671,6 @@ virSecurityDriver virSELinuxSecurityDriver = {
|
||||
.domainGetSecurityLabel = SELinuxGetSecurityLabel,
|
||||
.domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel,
|
||||
.domainSetSecurityLabel = SELinuxSetSecurityLabel,
|
||||
.domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
|
||||
.domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user