[libvirt] [PATCH 2/2] Set labelling for character devices in security drivers

Daniel P. Berrange berrange at redhat.com
Thu Jun 24 15:01:41 UTC 2010


When configuring serial, parallel, console or channel devices
with a file, dev or pipe backend type, it is neccessary to label
the file path in the security drivers. For char devices of type
file, it is neccessary to pre-create (touch) the file if it does
not already exist since QEMU won't be allowed todo so itself.
dev/pipe configs already require the admin to pre-create before
starting the guest.

* src/qemu/qemu_security_dac.c: set file ownership for character
  devices
* src/security/security_selinux.c: Set file labelling for character
  devices
* src/qemu/qemu_driver.c: Add character devices to cgroup ACL
---
 src/qemu/qemu_driver.c          |   59 +++++++++++++++++++
 src/qemu/qemu_security_dac.c    |  117 ++++++++++++++++++++++++++++++++++++++
 src/security/security_selinux.c |  119 +++++++++++++++++++++++++++++++++++++++
 src/util/cgroup.c               |    2 +-
 4 files changed, 296 insertions(+), 1 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a7b3f25..6274d4c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2950,6 +2950,28 @@ qemuPrepareHostDevices(struct qemud_driver *driver,
 }
 
 
+static int
+qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                         virDomainChrDefPtr dev,
+                         void *opaque ATTRIBUTE_UNUSED)
+{
+    int fd;
+    if (dev->type != VIR_DOMAIN_CHR_TYPE_FILE)
+        return 0;
+
+    if ((fd = open(dev->data.file.path, O_CREAT | O_APPEND, S_IRUSR|S_IWUSR)) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to pre-create chardev file %s"),
+                             dev->data.file.path);
+        return -1;
+    }
+
+    close(fd);
+
+    return 0;
+}
+
+
 static void
 qemudReattachManagedDevice(pciDevice *dev)
 {
@@ -3124,6 +3146,30 @@ cleanup:
 }
 
 
+static int qemuSetupChardevCgroup(virDomainDefPtr def,
+                                  virDomainChrDefPtr dev,
+                                  void *opaque)
+{
+    virCgroupPtr cgroup = opaque;
+    int rc;
+
+    if (dev->type != VIR_DOMAIN_CHR_TYPE_DEV)
+        return 0;
+
+
+    VIR_DEBUG("Process path %s for disk", dev->data.file.path);
+    rc = virCgroupAllowDevicePath(cgroup, dev->data.file.path);
+    if (rc != 0) {
+        virReportSystemError(-rc,
+                             _("Unable to allow device %s for %s"),
+                             dev->data.file.path, def->name);
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int qemuSetupCgroup(struct qemud_driver *driver,
                            virDomainObjPtr vm)
 {
@@ -3191,6 +3237,12 @@ static int qemuSetupCgroup(struct qemud_driver *driver,
                 goto cleanup;
             }
         }
+
+        if (virDomainChrDefForeach(vm->def,
+                                   true,
+                                   qemuSetupChardevCgroup,
+                                   cgroup) < 0)
+            goto cleanup;
     }
 
 done:
@@ -3364,6 +3416,13 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     if (qemuPrepareHostDevices(driver, vm->def) < 0)
         goto cleanup;
 
+    DEBUG0("Preparing chr devices");
+    if (virDomainChrDefForeach(vm->def,
+                               true,
+                               qemuPrepareChardevDevice,
+                               NULL) < 0)
+        goto cleanup;
+
     /* If you are using a SecurityDriver with dynamic labelling,
        then generate a security label for isolation */
     DEBUG0("Generating domain security label (if required)");
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index ffc9b8d..95015b0 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -328,6 +328,100 @@ done:
 
 
 static int
+qemuSecurityDACSetChardevLabel(virDomainObjPtr vm,
+                               virDomainChrDefPtr dev)
+
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    char *in = NULL, *out = NULL;
+    int ret = -1;
+
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+        return 0;
+
+    switch (dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        ret = qemuSecurityDACSetOwnership(dev->data.file.path, driver->user, driver->group);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
+            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
+            virReportOOMError();
+            goto done;
+        }
+        if ((qemuSecurityDACSetOwnership(in, driver->user, driver->group) < 0) ||
+            (qemuSecurityDACSetOwnership(out, driver->user, driver->group) < 0))
+            goto done;
+        ret = 0;
+        break;
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    VIR_FREE(in);
+    VIR_FREE(out);
+    return ret;
+}
+
+static int
+qemuSecurityDACRestoreChardevLabel(virDomainObjPtr vm,
+                                   virDomainChrDefPtr dev)
+
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    char *in = NULL, *out = NULL;
+    int ret = -1;
+
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+        return 0;
+
+    switch (dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        ret = qemuSecurityDACRestoreSecurityFileLabel(dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
+            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
+            virReportOOMError();
+            goto done;
+        }
+        if ((qemuSecurityDACRestoreSecurityFileLabel(out) < 0) ||
+            (qemuSecurityDACRestoreSecurityFileLabel(in) < 0))
+            goto done;
+        ret = 0;
+        break;
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    VIR_FREE(in);
+    VIR_FREE(out);
+    return ret;
+}
+
+
+static int
+qemuSecurityDACRestoreChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                      virDomainChrDefPtr dev,
+                                      void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+
+    return qemuSecurityDACRestoreChardevLabel(vm, dev);
+}
+
+
+static int
 qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
                                        int migrated)
 {
@@ -352,6 +446,12 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
             rc = -1;
     }
 
+    if (virDomainChrDefForeach(vm->def,
+                               false,
+                               qemuSecurityDACRestoreChardevCallback,
+                               vm) < 0)
+        rc = -1;
+
     if (vm->def->os.kernel &&
         qemuSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
         rc = -1;
@@ -365,6 +465,17 @@ qemuSecurityDACRestoreSecurityAllLabel(virDomainObjPtr vm,
 
 
 static int
+qemuSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                      virDomainChrDefPtr dev,
+                                      void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+
+    return qemuSecurityDACSetChardevLabel(vm, dev);
+}
+
+
+static int
 qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
 {
     int i;
@@ -384,6 +495,12 @@ qemuSecurityDACSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path AT
             return -1;
     }
 
+    if (virDomainChrDefForeach(vm->def,
+                               true,
+                               qemuSecurityDACSetChardevCallback,
+                               vm) < 0)
+        return -1;
+
     if (vm->def->os.kernel &&
         qemuSecurityDACSetOwnership(vm->def->os.kernel,
                                     driver->user,
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 2b43f2d..d4e2edb 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -628,6 +628,101 @@ done:
     return ret;
 }
 
+
+static int
+SELinuxSetSecurityChardevLabel(virDomainObjPtr vm,
+                               virDomainChrDefPtr dev)
+
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    char *in = NULL, *out = NULL;
+    int ret = -1;
+
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+        return 0;
+
+    switch (dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        ret = SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
+            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
+            virReportOOMError();
+            goto done;
+        }
+        if ((SELinuxSetFilecon(in, secdef->imagelabel) < 0) ||
+            (SELinuxSetFilecon(out, secdef->imagelabel) < 0))
+            goto done;
+        ret = 0;
+        break;
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    VIR_FREE(in);
+    VIR_FREE(out);
+    return ret;
+}
+
+static int
+SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm,
+                                   virDomainChrDefPtr dev)
+
+{
+    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
+    char *in = NULL, *out = NULL;
+    int ret = -1;
+
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+        return 0;
+
+    switch (dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        ret = SELinuxSetFilecon(dev->data.file.path, secdef->imagelabel);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
+            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
+            virReportOOMError();
+            goto done;
+        }
+        if ((SELinuxRestoreSecurityFileLabel(out) < 0) ||
+            (SELinuxRestoreSecurityFileLabel(in) < 0))
+            goto done;
+        ret = 0;
+        break;
+
+    default:
+        ret = 0;
+        break;
+    }
+
+done:
+    VIR_FREE(in);
+    VIR_FREE(out);
+    return ret;
+}
+
+
+static int
+SELinuxRestoreSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                      virDomainChrDefPtr dev,
+                                      void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+
+    return SELinuxRestoreSecurityChardevLabel(vm, dev);
+}
+
+
 static int
 SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
                                int migrated ATTRIBUTE_UNUSED)
@@ -652,6 +747,12 @@ SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
             rc = -1;
     }
 
+    if (virDomainChrDefForeach(vm->def,
+                               false,
+                               SELinuxRestoreSecurityChardevCallback,
+                               vm) < 0)
+        rc = -1;
+
     if (vm->def->os.kernel &&
         SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
         rc = -1;
@@ -858,6 +959,18 @@ SELinuxClearSecuritySocketLabel(virSecurityDriverPtr drv,
     return 0;
 }
 
+
+static int
+SELinuxSetSecurityChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                  virDomainChrDefPtr dev,
+                                  void *opaque)
+{
+    virDomainObjPtr vm = opaque;
+
+    return SELinuxSetSecurityChardevLabel(vm, dev);
+}
+
+
 static int
 SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_UNUSED)
 {
@@ -882,6 +995,12 @@ SELinuxSetSecurityAllLabel(virDomainObjPtr vm, const char *stdin_path ATTRIBUTE_
             return -1;
     }
 
+    if (virDomainChrDefForeach(vm->def,
+                               true,
+                               SELinuxSetSecurityChardevCallback,
+                               vm) < 0)
+        return -1;
+
     if (vm->def->os.kernel &&
         SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0)
         return -1;
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index 35e9691..33610aa 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -272,7 +272,7 @@ static int virCgroupSetValueStr(virCgroupPtr group,
     if (rc != 0)
         return rc;
 
-    VIR_DEBUG("Set value %s", keypath);
+    VIR_DEBUG("Set value '%s' to '%s'", keypath, value);
     rc = virFileWriteStr(keypath, value);
     if (rc < 0) {
         DEBUG("Failed to write value '%s': %m", value);
-- 
1.6.6.1




More information about the libvir-list mailing list