]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Set labelling for character devices in security drivers
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 23 Jun 2010 15:17:15 +0000 (16:17 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 25 Jun 2010 13:39:54 +0000 (14:39 +0100)
When configuring serial, parallel, console or channel devices
with a file, dev or pipe backend type, it is necessary 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 labeling for character
  devices
* src/qemu/qemu_driver.c: Add character devices to cgroup ACL

src/qemu/qemu_driver.c
src/qemu/qemu_security_dac.c
src/security/security_selinux.c
src/util/cgroup.c

index 9f4e08228a786d7510ac0193d4d4295b82bd90df..dcfab42189e48d2d705ee9794bf42f33dcf3262d 100644 (file)
@@ -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)
 {
@@ -3035,7 +3057,7 @@ static int qemuSetupDiskCgroup(virCgroupPtr cgroup,
         virStorageFileMetadata meta;
         int rc;
 
-        VIR_DEBUG("Process path %s for disk", path);
+        VIR_DEBUG("Process path '%s' for disk", path);
         rc = virCgroupAllowDevicePath(cgroup, path);
         if (rc != 0) {
             /* Get this for non-block devices */
@@ -3085,7 +3107,7 @@ static int qemuTeardownDiskCgroup(virCgroupPtr cgroup,
         virStorageFileMetadata meta;
         int rc;
 
-        VIR_DEBUG("Process path %s for disk", path);
+        VIR_DEBUG("Process path '%s' for disk", path);
         rc = virCgroupDenyDevicePath(cgroup, path);
         if (rc != 0) {
             /* Get this for non-block devices */
@@ -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)");
index ffc9b8d8b53eeefb2d1a658d24d40aebe6de1b2d..95015b091b2ca8ed5977a705e8b5ba1028c0ea6e 100644 (file)
@@ -327,6 +327,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;
@@ -364,6 +464,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)
 {
@@ -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,
index 2b43f2d02d2ad462fc62dc921c36776e3faf78d1..d4e2edbe1fa75d17a0a20481c3b1194fed23fe9b 100644 (file)
@@ -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;
index 177433c03f94422df7c5d4ba7df87e01251e585a..62b14465b0e4e039672c9063a05c66907d6ecc3d 100644 (file)
@@ -274,7 +274,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);