* 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 --- src/qemu_driver.c | 12 ++- src/security.h | 7 ++ src/security_selinux.c | 175 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 174 insertions(+), 20 deletions(-) diff --git a/src/qemu_driver.c b/src/qemu_driver.c index e9a09df..d75e28e 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -5498,6 +5498,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: @@ -5566,9 +5569,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: @@ -5958,8 +5958,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; } diff --git a/src/security.h b/src/security.h index 5fc3086..40f9d95 100644 --- a/src/security.h +++ b/src/security.h @@ -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 diff --git a/src/security_selinux.c b/src/security_selinux.c index 3b2e88f..5b7b038 100644 --- a/src/security_selinux.c +++ b/src/security_selinux.c @@ -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, @@ -393,6 +385,27 @@ err: } 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, virDomainDiskDefPtr disk) @@ -414,6 +427,126 @@ 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 +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: + 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, 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 +555,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 +623,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 +644,6 @@ virSecurityDriver virSELinuxSecurityDriver = { .domainGetSecurityLabel = SELinuxGetSecurityLabel, .domainRestoreSecurityLabel = SELinuxRestoreSecurityLabel, .domainSetSecurityLabel = SELinuxSetSecurityLabel, + .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel, + .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel, }; -- 1.6.2.5 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list