[libvirt] [PATCH 4/6] Support relabelling of USB and PCI devices

Daniel P. Berrange berrange at redhat.com
Tue Sep 1 15:28:57 UTC 2009


* 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




More information about the libvir-list mailing list