* 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