]> xenbits.xensource.com Git - libvirt.git/commitdiff
blockjob: allow mirroring under SELinux and cgroup
authorEric Blake <eblake@redhat.com>
Sat, 27 Oct 2012 13:32:19 +0000 (07:32 -0600)
committerEric Blake <eblake@redhat.com>
Sat, 27 Oct 2012 13:43:39 +0000 (07:43 -0600)
Use the recent addition of qemuDomainPrepareDiskChainElement to
obtain locking manager lease, permit a block device through cgroups,
and set the SELinux label; then audit the fact that we hand a new
file over to qemu.  Alas, releasing the lease and label at the end
of the mirroring is a trickier prospect (we would have to trace the
backing chain of both source and destination, and be sure not to
revoke rights to any part of the chain that is shared), so for now,
virDomainBlockJobAbort still leaves things with additional access
granted (as block-pull and block-commit have the same problem of
not clamping access after completion, a future cleanup would cover
all three commands).

* src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set up labeling.

src/qemu/qemu_driver.c

index 668c8485eabab88bc56293ccc0788463574557fd..bde3204bb82099ed9dce8138aed0b8c5cfb2c11b 100644 (file)
@@ -12866,6 +12866,9 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
     int ret = -1;
     int idx;
     struct stat st;
+    bool need_unlink = false;
+    char *mirror = NULL;
+    virCgroupPtr cgroup = NULL;
 
     /* Preliminaries: find the disk we are editing, sanity checks */
     virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
@@ -12880,6 +12883,13 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
                        _("domain is not running"));
         goto cleanup;
     }
+    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
+        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Unable to find cgroup for %s"),
+                       vm->def->name);
+        goto cleanup;
+    }
 
     device = qemuDiskPathToAlias(vm, path, &idx);
     if (!device) {
@@ -12951,51 +12961,74 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
         goto endjob;
     }
 
-    /* XXX We also need to add security labeling, lock manager lease,
-     * and auditing of those events.  */
-    if (!format) {
-        if (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) {
-            /* If the user passed the REUSE_EXT flag, then either they
-             * also passed the RAW flag (and format is non-NULL), or
-             * it is safe for us to probe the format from the file
-             * that we will be using.  */
-            disk->mirrorFormat = virStorageFileProbeFormat(dest, driver->user,
-                                                           driver->group);
-        } else {
+    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
+        int fd = qemuOpenFile(driver, dest, O_WRONLY | O_TRUNC | O_CREAT,
+                              &need_unlink, NULL);
+        if (fd < 0)
+            goto endjob;
+        VIR_FORCE_CLOSE(fd);
+        if (!format)
             disk->mirrorFormat = disk->format;
-        }
-        if (disk->mirrorFormat > 0)
-            format = virStorageFileFormatTypeToString(disk->mirrorFormat);
-    } else {
+    } else if (format) {
         disk->mirrorFormat = virStorageFileFormatTypeFromString(format);
         if (disk->mirrorFormat <= 0) {
             virReportError(VIR_ERR_INVALID_ARG, _("unrecognized format '%s'"),
                            format);
             goto endjob;
         }
-    }
+    } else {
+        /* If the user passed the REUSE_EXT flag, then either they
+         * also passed the RAW flag (and format is non-NULL), or it is
+         * safe for us to probe the format from the file that we will
+         * be using.  */
+        disk->mirrorFormat = virStorageFileProbeFormat(dest, driver->user,
+                                                       driver->group);
+    }
+    if (!format && disk->mirrorFormat > 0)
+        format = virStorageFileFormatTypeToString(disk->mirrorFormat);
     if (!(disk->mirror = strdup(dest))) {
         virReportOOMError();
         goto endjob;
     }
 
+    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
+                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
+        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
+                                          VIR_DISK_CHAIN_NO_ACCESS);
+        goto endjob;
+    }
+
     /* Actually start the mirroring */
     qemuDomainObjEnterMonitor(driver, vm);
     ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
                                  flags);
+    virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
     qemuDomainObjExitMonitor(driver, vm);
+    if (ret < 0) {
+        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
+                                          VIR_DISK_CHAIN_NO_ACCESS);
+        goto endjob;
+    }
+
+    /* Update vm in place to match changes.  */
+    need_unlink = false;
+    disk->mirror = mirror;
+    mirror = NULL;
 
 endjob:
-    if (ret < 0) {
-        VIR_FREE(disk->mirror);
+    if (need_unlink && unlink(dest))
+        VIR_WARN("unable to unlink just-created %s", dest);
+    if (ret < 0)
         disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
-    }
+    VIR_FREE(mirror);
     if (qemuDomainObjEndJob(driver, vm) == 0) {
         vm = NULL;
         goto cleanup;
     }
 
 cleanup:
+    if (cgroup)
+        virCgroupFree(&cgroup);
     VIR_FREE(device);
     if (vm)
         virDomainObjUnlock(vm);