Use the recent addition of qemuDomainPrepareDiskChainElement to
set the SELinux label, obtain locking manager lease, permit a block
device through cgroups, and 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 (cleaning this up in the future should also improve
block-pull and block-commit).
* src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set up labeling.
---
v8: simplify, based on additions in block-commit series
src/qemu/qemu_driver.c | 71 ++++++++++++++++++++++++++++++++++++--------------
1 file changed, 52 insertions(+), 19 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 13cba61..f2ff931 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12861,6 +12861,9 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
int idx;
bool reopen;
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 |
@@ -12875,6 +12878,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) {
@@ -12947,51 +12957,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 */
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
reopen, flags);
+ virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
qemuDomainObjExitMonitorWithDriver(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);
--
1.7.11.7